Sep 23, 2026·5 min read·23 visits
Unauthenticated remote attackers can execute high-speed brute-force attacks against LightRAG's /login endpoint to compromise administrative credentials, or concurrently flood the endpoint to exhaust CPU resources and cause a Denial of Service due to a lack of rate limiting and thread-blocking bcrypt executions.
LightRAG prior to version 1.5.5 does not implement rate limiting, lockout mechanisms, or throttling on its `/login` authentication endpoint. This allows unauthenticated remote attackers to perform rapid brute-force attacks to crack passwords and hijack active sessions. Furthermore, because the endpoint processed synchronous bcrypt verifications inside an asynchronous event loop, concurrent brute-force requests can easily exhaust server CPU resources, triggering an unauthenticated Denial of Service (DoS).
LightRAG is an open-source framework designed for retrieval-augmented generation. It exposes a web-based API endpoint at /login inside the lightrag/api/lightrag_server.py component to handle administrative and user authentication.
Prior to version 1.5.5, this authentication endpoint operated without any rate-limiting controls, failure counters, or account lockout mechanisms. The lack of throttling exposes the system's entry point to automated high-frequency brute-force attacks.
An unauthenticated remote attacker can exploit this design flaw to systematically guess passwords at maximum network speed. Successful credential recovery exposes the private data stored within LightRAG, including the internal knowledge graph, vector store indexes, and primary administrative configurations.
The fundamental flaw resides within lightrag/api/lightrag_server.py under the handler for the POST /login endpoint. The server parsed incoming authentication credentials and invoked the verify_password function without performing any intermediate state validation on the origin IP address or the requested username.
This behavior classifies as CWE-307: Improper Restriction of Excessive Authentication Attempts. Because the endpoint lacked a stateful history of failed attempts, it immediately processed every authentication request, verifying credentials against the stored password hashes.
Additionally, the verification process utilizes the CPU-bound bcrypt hashing function. In asynchronous Python frameworks such as FastAPI and Uvicorn, CPU-intensive operations executed synchronously inside the main event loop block the single thread. An attacker sending concurrent login requests forces the server to spend excessive clock cycles on bcrypt computations, starving the event loop and preventing the application from serving legitimate traffic.
Before the remediation in version 1.5.5, the /login route directly called the blocking verification helper in the main thread without checking any rate-limiting state:
# Vulnerable Implementation
@app.post("/login")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
# Blocking bcrypt execution in the main async thread
password_ok = auth_handler.verify_password(form_data.username, form_data.password)
if not password_ok:
raise HTTPException(status_code=401, detail="Incorrect credentials")
# Generate token...The patch introduced in version 1.5.5 resolves both the lack of brute-force protection and the event-loop blocking issue. First, it implements a sliding-window memory tracker LoginRateLimiter that maintains failures per unique IP and username. Second, it shifts the CPU-bound bcrypt verification to a separate worker thread using asyncio.to_thread:
# Patched Implementation inside lightrag/api/lightrag_server.py
client_ip = request.client.host if request.client else "unknown"
rate_limit_key = f"{client_ip}:{username}"
# Pre-flight rate limit check
retry_after = login_rate_limiter.retry_after(rate_limit_key)
if retry_after is not None:
raise HTTPException(
status_code=429,
detail="Too many failed login attempts. Please try again later.",
headers={"Retry-After": str(int(retry_after) + 1)},
)
# Non-blocking CPU execution on an auxiliary worker thread
password_ok = await asyncio.to_thread(
auth_handler.verify_password, username, form_data.password
)
if not password_ok:
login_rate_limiter.record_failure(rate_limit_key)
raise HTTPException(status_code=401, detail="Incorrect credentials")By checking the rate limiter before executing asyncio.to_thread, the application avoids the computational cost of bcrypt for blacklisted clients. This effectively mitigates the CPU-exhaustion denial-of-service vector.
An attacker can exploit this vulnerability using programmatic automated tools. The attack relies on sending repeated POST HTTP requests to the /login endpoint containing targeted username guesses and a credential dictionary.
The following simple proof-of-concept Python script demonstrates the lack of throttling on vulnerable targets:
import requests
import time
target_url = "http://localhost:8020/login"
credentials = {"username": "admin", "password": "wrong_password_attempt"}
for attempt in range(1, 20):
start_time = time.time()
response = requests.post(target_url, data=credentials)
duration = time.time() - start_time
print(f"Attempt {attempt}: Status {response.status_code} in {duration:.2f}s")On a vulnerable host, all 20 requests return HTTP status 401 Unauthorized without any delay or lockouts. On a patched instance, attempts beyond the 5-request limit return HTTP status 429 Too Many Requests.
The impact of successful exploitation is critical. By successfully brute-forcing administrative credentials, an attacker obtains a valid JWT authorization token.
This token grants administrative access to LightRAG's central functionalities. Attackers can read sensitive internal corporate documents parsed by the engine, query the proprietary global knowledge graph, and perform arbitrary document uploads or deletions.
Furthermore, the accompanying availability impact is highly practical. Because the system can be forced to run intensive bcrypt operations continuously, an unauthenticated attacker can effectively lock the application server in a perpetual busy-loop, rendering the RAG platform completely unresponsive to integration workflows.
To resolve this vulnerability, organizations must upgrade LightRAG to version 1.5.5 or higher. The patch introduces configurable parameters to adjust the login lockout thresholds:
LOGIN_MAX_FAILED_ATTEMPTS (Default: 5)LOGIN_LOCKOUT_WINDOW_SECONDS (Default: 300.0)While the sliding-window memory check resolves direct single-IP attacks, security teams must recognize its architectural limitations. Because the tracking dictionary is kept strictly in volatile RAM, restarting the container clears all lockouts. Additionally, in multi-process setups (such as Gunicorn running multiple Uvicorn workers), each worker maintains a separate state, multiplying the effective threshold by the worker count.
Furthermore, attackers operating from distributed botnets or rotating IP proxies can bypass the per-IP constraints. To completely secure the platform, deploy LightRAG behind a dedicated reverse proxy or Web Application Firewall (WAF) such as Nginx or Cloudflare. Configure rate-limiting rules directly at the proxy tier on the /login path to apply unified, persistent blocking policies.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
LightRAG HKUDS | < 1.5.5 | 1.5.5 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-307: Improper Restriction of Excessive Authentication Attempts |
| Attack Vector | Network |
| CVSS Score | 9.1 (Critical) |
| Impact | Account Takeover and CPU-Exhaustion DoS |
| Exploit Status | PoC available, easily automatable |
| CISA KEV Status | No |
The program does not limit the number of times an actor can attempt to authenticate, which makes it susceptible to brute-force attacks.
Canonical LXD and LXC Incus contain an arbitrary file write vulnerability (CWE-73 / CWE-59) in the `/1.0/instances/<name>/exec` REST API endpoint. When an instance is unpacked from an image archive, top-level symbolic links are extracted directly onto the host filesystem within the instance storage directory. If a crafted image includes a symbolic link named `exec-output` pointing to an arbitrary host path, invoking the execution endpoint with `record-output: true` causes the privileged host daemon to follow the symlink and write command output files directly to the target host directory. An authenticated attacker with permissions to import images and execute commands can exploit this flaw to write controlled content to sensitive host directories such as `/etc/cron.d`, resulting in arbitrary code execution on the host as `root`.
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.