Skip to content

fix(backend): prevent path traversal in SPA catch-all route (#126)#135

Open
AAtomical wants to merge 1 commit into
HKUDS:mainfrom
AAtomical:fix/spa-path-traversal
Open

fix(backend): prevent path traversal in SPA catch-all route (#126)#135
AAtomical wants to merge 1 commit into
HKUDS:mainfrom
AAtomical:fix/spa-path-traversal

Conversation

@AAtomical
Copy link
Copy Markdown

Summary

Fixes #126 — arbitrary file read via path traversal in the Docker/production SPA catch-all route GET /{full_path:path} in new_ui/backend/main.py.

The route joined the caller-supplied full_path directly onto FRONTEND_DIST and called exists()/is_file() on the un-resolved path. pathlib's / join does not strip .. segments, and percent-encoded separators (%2F) and dots (%2E%2E) survive Starlette's URL normalisation because the path parameter is decoded after routing. An unauthenticated client could read any file the process could access (SSH keys, secrets, /etc/passwd) outside the build directory.

Fix

Resolve the joined path and verify it stays within the resolved FRONTEND_DIST using is_relative_to before serving; otherwise fall back to index.html. is_relative_to requires Python 3.9+, matching setup.py's python_requires>=3.9.

Verification

Reproduced the original leak and confirmed the fix blocks it via a FastAPI TestClient against both old and new handlers:

Request Before After
GET /app.js (legit asset) 200, served 200, served
GET /..%2F..%2F..%2Fsecret_key 200, key leaked 200, index.html (no leak)

The Docker/production catch-all route `GET /{full_path:path}` joined the
caller-supplied path directly onto FRONTEND_DIST and called exists()/is_file()
on the un-resolved path. pathlib's "/" join does not strip ".." segments, and
percent-encoded separators (%2F) and dots (%2E%2E) survive Starlette's URL
normalisation because the path parameter is decoded after routing. This let an
unauthenticated client read any file the process could access (SSH keys,
secrets, /etc/passwd) outside the frontend build directory.

Resolve the joined path and verify it stays within the resolved FRONTEND_DIST
via is_relative_to before serving; otherwise fall back to index.html.

Fixes HKUDS#126
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]:Arbitrary File Read via Path Traversal in SPA Catch-All Route (/{full_path:path}) — Docker/Production Mode

1 participant