fix(security): validate Postman collection/environment ids, block path transversal - #1158
Open
FabioLeitao wants to merge 1 commit into
Open
Conversation
…h traversal
postman:// targets took collection_uid/environment_uid as raw netloc+path with
no format check. requests collapses ".." in a URL path before sending the
request, so fetch_postman_collection/fetch_postman_environment built
`{POSTMAN_API_BASE}/collections/{uid}` (and /environments/{uid}) with an
attacker-controlled string that could traverse to an arbitrary Postman API
endpoint -- authenticated with the caller's own POSTMAN_API_KEY via X-Api-Key.
Confirmed with requests.Request(...).prepare().url:
'https://api.getpostman.com/collections/x/../../workspaces'
-> 'https://api.getpostman.com/workspaces'
Also: a successfully-fetched collection was written with the default umask
(world-readable on a shared host) even though it can carry saved auth
headers/tokens, while this codebase already has write_secret_text (0600) for
exactly this kind of data in three other call sites.
Fix:
- validate_postman_uid() (letters/digits/hyphens only, matching real Postman
uid shape) enforced both at target-parse time (fail fast, clear error) and
inside fetch_postman_collection/fetch_postman_environment (defense in depth
for any other caller).
- write_fetched_collection now uses write_secret_text instead of
Path.write_text.
Full test suite: 1058 passed. mypy/ruff clean on touched files. 6 new tests
cover the traversal rejection (asserting requests.get is never called),
an @-authority variant, and the file-permission fix.
Author
|
Human-Reviewed-By: @FabioLeitao (#1158) |
Contributor
Greptile SummaryThis PR hardens Postman target handling and protects fetched collection contents.
Confidence Score: 5/5The PR appears safe to merge, with no actionable regressions identified in the changed paths. The new validation accepts the documented Postman UID forms while blocking path separators and other unsafe characters, and the secret-file writer preserves required directory creation and overwrite behavior while improving permissions and symlink safety. Important Files Changed
Reviews (1): Last reviewed commit: "fix(security): validate Postman collecti..." | Re-trigger Greptile |
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.
Validate Postman collection/environment ids, block path traversal
postman:// targets took collection_uid/environment_uid as raw netloc+path with no format check. requests collapses ".." in a URL path before sending the request, so fetch_postman_collection/fetch_postman_environment built
{POSTMAN_API_BASE}/collections/{uid}(and /environments/{uid}) with an attacker-controlled string that could traverse to an arbitrary Postman API endpoint -- authenticated with the caller's own POSTMAN_API_KEY via X-Api-Key.Confirmed with requests.Request(...).prepare().url:
'https://api.getpostman.com/collections/x/../../workspaces'
-> 'https://api.getpostman.com/workspaces'
Also: a successfully-fetched collection was written with the default umask (world-readable on a shared host) even though it can carry saved auth headers/tokens, while this codebase already has write_secret_text (0600) for exactly this kind of data in three other call sites.
Fix:
Full test suite: 1058 passed. mypy/ruff clean on touched files. 6 new tests cover the traversal rejection (asserting requests.get is never called), an @-authority variant, and the file-permission fix.