Repository navigation
Reject package requests with ? or # in the decoded path - #437
Merged
Merged
Conversation
…e middleware in front of every ecosystem mount. Handlers build the upstream URL from the decoded path, so busybox.apk%3F/foo-9.9-r0.apk fetched busybox but cached it as foo; PyPI could be poisoned the same way, and the other ecosystems stored files under mangled names past the denylist and cooldown.
…e the upstream URL from metadata, and with git-pkgs#433 a branch like dev-fix/git-pkgs#42 is requested as dev-fix%2F%2342. Adversarial review finding F1.
andrew
approved these changes
Oct 12, 2026
andrew
left a comment
Contributor
There was a problem hiding this comment.
The guard covers the ecosystem mounts and preserves Composer branch downloads. No changes requested.
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.
Handlers build upstream URLs from the decoded request path. An encoded
?or#therefore ends the path upstream but not in the proxy:GET /apk/alpine/v3.22/main/x86_64/busybox-1.37.0-r12.apk%3F/foo-9.9-r0.apkfetches busybox and caches it as
foo@9.9-r0. Later clients asking for foo get busybox, and the denylist never sees busybox. PyPI can be poisoned the same way. Maven, Conda, CRAN, Gem, Hex, Pub and Go end up storing files under mangled names, which gets around the denylist and cooldown.This adds one middleware in front of every ecosystem mount that answers such paths with 400, so new handlers are covered too. Composer archive downloads are let through: their upstream URL comes from the metadata, and git branches like
dev-fix/#42reach the proxy asdev-fix%2F%2342(see #433).A server test sends a crafted path to every mount and checks for 400 with no upstream request. Without the middleware, most of them get through.