fix(backend): prevent path traversal in SPA catch-all route (#126)#135
Open
AAtomical wants to merge 1 commit into
Open
fix(backend): prevent path traversal in SPA catch-all route (#126)#135AAtomical wants to merge 1 commit into
AAtomical wants to merge 1 commit into
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #126 — arbitrary file read via path traversal in the Docker/production SPA catch-all route
GET /{full_path:path}innew_ui/backend/main.py.The route joined the caller-supplied
full_pathdirectly ontoFRONTEND_DISTand calledexists()/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_DISTusingis_relative_tobefore serving; otherwise fall back toindex.html.is_relative_torequires Python 3.9+, matchingsetup.py'spython_requires>=3.9.Verification
Reproduced the original leak and confirmed the fix blocks it via a FastAPI
TestClientagainst both old and new handlers:GET /app.js(legit asset)GET /..%2F..%2F..%2Fsecret_key