fix: prevent path traversal via Gitea ref/sha/base/head parameters #18
Reference in New Issue
Block a user
Delete Branch "fix/gitea-ref-path-traversal"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The ref-like tool arguments (ref, sha, base, head) were only length-limited
and were interpolated unencoded into Gitea API URL paths (get_tree,
get_commit_diff, compare_refs). Because httpx collapses ".." path segments
(RFC 3986), a crafted value such as "../../../../owner/repo/contents/secret"
escaped the declared owner/repo prefix. In service-PAT mode this allowed a
user authorized on one repository to read arbitrary repositories the service
token could reach, and in OAuth mode it bypassed the policy engine's
per-repository rules (which never see ref values).
Two defense layers:
segments, leading "/", backslashes, null bytes, control chars, whitespace,
and "?"/"#", while preserving legitimate slash refs (feature/foo, v1.2.3).
This is what actually closes the traversal.
(safe="") and ref/sha/base/head/filepath (safe="/") in every repo URL
builder, mirroring the existing pattern in server.py.
Tests: negative cases for traversal/unsafe chars across all four fields,
positive cases for slash-containing refs, length-bound regression, and a
URL-layer confinement check. Full suite green (176 passed), coverage 85.64%.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com