khoj has an unauthenticated path traversal in /home/ endpoint that allows file read from server filesystemGHSA-62mm-xwmv-crhg
Fix: khoj-ai/khoj@21c51b9GHSA-62mm-xwmv-crhg is a security vulnerability in khoj. A fix is available for khoj — see the affected versions and patch details below.
Real-World Exposure
khojReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.
Description
Summary
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
FileResponsedoes 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 Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐍PyPI | khoj | ≥ 2.0.0-beta.23&&< 2.0.0-beta.25 | 2.0.0-beta.25pip install --upgrade 'khoj==2.0.0-beta.25' |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for khoj, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update khoj to 2.0.0-beta.25 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-62mm-xwmv-crhg is resolved across your whole dependency graph.
Workarounds
Resolve every user-supplied path to its canonical form and reject anything that escapes the intended directory, and run the component under an account that has no read or write access outside the directory it legitimately serves.
Frequently Asked Questions
Is GHSA-62mm-xwmv-crhg in your dependencies?
Find it across PyPI, including transitive dependencies.