Sep 23, 2026·5 min read·15 visits
Unauthenticated remote timing side-channels in HKUDS LightRAG authentication logic permit username enumeration and plaintext password recovery.
HKUDS LightRAG prior to version 1.5.5 is vulnerable to multiple timing side-channels (CWE-208) in its API authentication layer. The password verification logic in `lightrag/api/passwords.py` compares plaintext administrative credentials using Python's short-circuiting equality operator (`==`). Additionally, `lightrag/api/auth.py` terminates authentication early on non-existent usernames, creating an observable latency difference compared to computationally expensive bcrypt comparisons on valid accounts. Together, these allow remote unauthenticated attackers with low-latency network access to enumerate valid usernames and extract plaintext passwords character by character.
HKUDS LightRAG is an open-source framework designed for fast, retrieval-augmented generation (RAG) using large language models. To restrict access to administrative functions, the application exposes API endpoints protected by basic token authentication. The credentials are defined using the AUTH_ACCOUNTS configuration parameter.
Prior to version 1.5.5, the authentication mechanism exposed two major security weaknesses. The primary weakness (CWE-208) resides in the password verification routines, which compare plaintext administrative password strings without a constant-time algorithm. A secondary weakness allows an external attacker to reliably determine valid usernames by analyzing the processing time of authentication requests, bypass the primary layer, and recover plaintext credentials.
The vulnerability stems from two independent implementation details within the authentication layer. First, lightrag/api/passwords.py relies on Python's default equality operator (==) to match supplied passwords against stored plaintext values.
Python's string and byte equality checks optimize comparison performance using two techniques:
False immediately.False.Because of this short-circuiting behavior, the execution latency is directly proportional to the number of matching characters in the user's input. A guess that matches the first three characters of a password will take slightly longer to fail than a guess that mismatch on the first character.
Second, the authentication handler in lightrag/api/auth.py evaluates whether the user exists prior to executing password checking. When bcrypt hashing is enabled, verifying a valid user triggers bcrypt.checkpw, which executes in roughly 100 milliseconds. If the username does not exist, the routine returns False immediately in microseconds. This large difference in latency allows external observers to enumerate valid usernames.
In the vulnerable version of the codebase, password verification was implemented as a direct equality operation:
# Vulnerable implementation in lightrag/api/passwords.py
def verify_password(plain_password: str, stored_password: str) -> bool:
# ...
return stored_password == plain_passwordThis behavior is fixed in the patch by utilizing Python's hmac.compare_digest function. The corrected implementation enforces constant-time byte comparisons by processing the full length of the byte strings:
# Patched implementation in lightrag/api/passwords.py
import hmac
def verify_password(plain_password: str, stored_password: str) -> bool:
# ...
return hmac.compare_digest(
stored_password.encode("utf-8"), plain_password.encode("utf-8")
)Additionally, the username enumeration side-channel was resolved in lightrag/api/auth.py by integrating a dummy verification mechanism. If a username does not exist in the store, the application executes a verification pass against a static, synthetic bcrypt hash (_DUMMY_VERIFY_SPEC). This forces the server to spend identical computational time on invalid accounts:
# Patched implementation in lightrag/api/auth.py
_DUMMY_VERIFY_SPEC = (
BCRYPT_PASSWORD_PREFIX
+ "$2b$12$ilI0sY2jGfy4h0AVtn6WuutU6BFwzZq5MVvrQYY9fbyQ59NI2NBKa"
)
def verify_password(self, username: str, plain_password: str) -> bool:
stored_password = self.accounts.get(username)
if stored_password is None:
# Execute dummy verification to equalize execution time
verify_password(plain_password, _DUMMY_VERIFY_SPEC)
return False
return verify_password(plain_password, stored_password)To exploit these vulnerabilities, an attacker needs a network path with minimal jitter, such as co-location inside the same cloud region or container infrastructure. The attack is carried out in two distinct phases:
An attacker sends repetitive requests containing different candidate usernames to the /login endpoint. By sorting the returned network latencies, usernames that delay response times by roughly 100 milliseconds are marked as valid administrative accounts on systems configured with bcrypt.
Once a username is validated, the attacker attacks the plaintext comparison routine:
admin123 and the attacker sends aaaa, it fails immediately at index 0. Sending axxx fails at index 1, which requires slightly more time. Analyzing the latency distributions over a high number of requests isolates the correct character prefix, eventually reconstructing the credential.A successful attack compromises the confidentiality of administrative credentials for the LightRAG framework. This vulnerability possesses a CVSS 3.1 rating of 5.9 (Medium) with the vector CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N.
The attack complexity is designated as High (AC:H) because measuring sub-millisecond differences over a network requires precise statistical analysis, filtering algorithms, and low network latency. However, in containerized or shared network architectures, these requirements are met. Compromise of administrative passwords grants attackers write and read capabilities over the retrieval-augmented generation engine, including the ability to manipulate indexed documentation, execute prompt injections, and poison generative AI outputs.
The primary resolution is to upgrade HKUDS LightRAG to version 1.5.5 or higher, which integrates the constant-time comparisons and the dummy bcrypt executions.
Additionally, administrators must configure their deployment's passwords securely. When storing accounts in the AUTH_ACCOUNTS configurations, passwords must be formatted using cryptographic bcrypt hashes prefixed with the {bcrypt} tag. Plaintext values are discouraged, as any deployment storing unhashed passwords remains vulnerable to local configuration leakage and other password-recovery mechanisms.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
LightRAG HKUDS | < 1.5.5 | 1.5.5 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-208: Observable Timing Discrepancy |
| Attack Vector | Network (Low-latency / High-precision) |
| CVSS v3.1 | 5.9 (Medium) |
| Exploit Status | Proof-of-Concept |
| KEV Status | Not Listed |
| Impact | Administrative Credential Recovery & Username Enumeration |
The product performs an operation that takes a variable amount of time, and the security of the operation is dependent on that operation being completed in a constant amount of time.
CVE-2026-48749 (tracked as GHSA-vghh-5rfx-xhq8 for LXD and GHSA-2q3f-q5pq-g8wv for Incus) is a critical container escape vulnerability in the Canonical LXD and Linux Containers Incus system container managers. By importing a specially crafted container image archive containing duplicate tar member headers, an authenticated attacker can replace the instance rootfs directory with a symbolic link pointing to the underlying host root filesystem. When performing file operations on a stopped container, the privileged forkfile helper binary resolves the symbolic link without confinement and chroots directly into the host filesystem, granting arbitrary root-level file read and write access.
GHSA-fmc8-p6q7-75cc (associated with CVE-2026-48755) is a critical argument injection vulnerability in Canonical LXD (github.com/canonical/lxd). The vulnerability occurs during instance and storage volume backup operations when processing the user-supplied compression_algorithm configuration parameter. While LXD validates the primary executable token against an allowlist of supported compression binaries, it fails to sanitize or restrict subsequent tokens parsed via shellquote.Split. These additional arguments are passed directly to exec.Command. An authenticated attacker with privileges to trigger backups can inject command-line flags for utilities like zstd to read staged files from a container filesystem and write them to arbitrary paths on the underlying host filesystem, such as /etc/cron.d/, achieving root-level arbitrary code execution on the host.
A critical path traversal vulnerability caused by improper input validation (CWE-20) exists in the direct image download handler of Canonical LXD and Linux Containers Incus. When an authenticated user requests an image import using the URL source type, the daemon reads the image fingerprint from an untrusted HTTP response header (`Incus-Image-Hash` or `LXD-Image-Hash`) without validating that it conforms to a SHA-256 format. This unvalidated string is concatenated directly into a filesystem path via `filepath.Join` prior to file creation and cryptographic verification, allowing directory traversal sequences to write arbitrary files on the host filesystem as root.
CVE-2026-9639 (GHSA-j93m-3j9p-m5m8) is a null pointer dereference vulnerability in Canonical LXD affecting versions 5.0.0 through 5.21.4 and 6.0 through 6.8. The flaw resides in the (*lxdBackend).CreateCustomVolumeFromBackup method within lxd/storage/backend_lxd.go. An authenticated attacker with the can_create_storage_volumes permission can upload a crafted custom volume backup tarball that omits the expires_at field on a snapshot entry, triggering an unhandled SIGSEGV panic and terminating the LXD daemon.
An operating system command injection vulnerability (CWE-78) exists in GeoNode versions prior to 5.1.0. The vulnerability occurs in the vector upload processing pipeline when handling user-supplied geospatial files. By supplying a crafted layer name containing shell metacharacters, an authenticated attacker with basic data upload privileges can execute arbitrary commands on the underlying server or container hosting the GeoNode application and Celery worker processes.
GeoNode versions prior to 5.0.3 contain an unrestricted file upload vulnerability (CWE-434) within the document and dataset ingestion architecture. Authenticated low-privileged users can bypass upload validation via direct REST API interactions, file extension masquerading, metadata mutation via PATCH requests, or malicious archive submissions. This allows attackers to store and serve dangerous file types, alter on-disk file references, or trigger path traversal and resource exhaustion during archive extraction.