-
Notifications
You must be signed in to change notification settings - Fork 122
Prevent path traversal in control server patch applier (#2532) #2557
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
cretz
merged 2 commits into
basetenlabs:main
from
sam-shridhar1950f:harden-control-patch-path-traversal
Aug 13, 2026
Merged
Changes from 1 commit
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the contribution! Can you give me some background on how you came across this? Was this an issue you hit or just something you saw browsing open issues?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking a look! Just something I came across browsing the open issues — I wasn't hitting it in production. The security label on #2532 caught my eye, and since the fix was nicely scoped to a single sink (
apply_code_patch) with a clear containment invariant to enforce, it seemed like a good self-contained hardening PR to pick up. Happy to adjust scope or approach however you'd prefer.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am a bit concerned without having tested this against code patching against the backend (i.e.
truss push --watch/truss watch) any side effects it may have giving a qualified path hereThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch — the concern was valid: the check previously handed the fully-resolved path to the file operations, which changes what gets written/logged if the app dir sits behind a symlink. Fixed in 2db3c64:
_validate_withinnow uses resolved copies only for the containment check and returns the plainrelative_dir / patch.pathjoin, so the path handed tomkdir/write/unlink(and the log lines) is byte-for-byte identical to pre-PR behavior for every legitimate patch.To verify against the actual live-reload flow, I ran
test_control_truss_apply_patch(the Docker integration test that builds a control truss from the local templates, POSTs a realPatchRequestto/control/patch— the same server-side pathtruss push --watch/truss watchdrives — and asserts the model's predict output changes): 1 passed in 3:46. Also green locally: the patch-applier unit tests (19), the control server endpoint tests (35), and the client-side dir-patch applier tests (68).Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you a Baseten user and were you able to verify this against the Baseten server side platform by deploying/watching a model?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes — I'm a Baseten user, and I just verified this against the platform. I deployed a dev model from this branch's checkout (
truss push --watch) and exercised the live-reload flow end to end:model.py→Created patch to update model code file: model/model.py→patched successfully→ next predict returned the new output (no rebuild, same deployment)model/helpers/nested_util.py→ patched successfully, and the model imported it on reloadAll three round-tripped cleanly through
POST /control/patchon the deployed dev container.One caveat for full transparency: the dev image's control server is built by the Baseten backend from released truss, so the platform run pins down the exact behavior the released applier has today. As of 2db3c64 the containment check returns the identical unresolved
relative_dir / patch.pathjoin for every accepted patch — so for the entire flow verified above, the patched code is behavior-identical by construction. The only behavioral delta is rejecting paths that escape the target dir, and that path is covered by the unit tests plus the local Docker integration test (test_control_truss_apply_patch), which does bake this branch's control server into the container image.