fix(cookbook): validate model_dir segments in /api/model/cached#5529
Open
archdex-art wants to merge 1 commit into
Open
fix(cookbook): validate model_dir segments in /api/model/cached#5529archdex-art wants to merge 1 commit into
archdex-art wants to merge 1 commit into
Conversation
The /api/model/cached endpoint split model_dir on commas and normalized bare Linux paths, but never validated segments before embedding them into the generated scan script — unlike the sibling /api/model/download endpoint, which runs local_dir through _validate_local_dir. Extracts the split/normalize/validate logic into a new _parse_model_dirs() helper (routes/cookbook_helpers.py, alongside _validate_local_dir and _cached_model_scan_script, which it now composes) so both endpoints share identical validation: shell metacharacters and leading-dash (option injection) segments are rejected with a 400 instead of reaching the generated scanner. Paths were already embedded via Python repr rather than shell-interpolated, so this was not an RCE — but the inconsistency meant invalid paths could still trigger unintended filesystem walks. The route handler is now a one-line call: model_dirs = _parse_model_dirs(model_dir). Fixes odysseus-dev#5508
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
GET /api/model/cachedvalidateshostandssh_port(validate_remote_host,validate_ssh_port) but never validated themodel_dirquery param before splitting it on commas and embedding each segment into the generated cache-scan script — unlike the siblingPOST /api/model/downloadendpoint, which runs itslocal_dirparam through_validate_local_dir. Paths reach the generated script via Pythonrepr()rather than shell interpolation, so this was not a shell-injection RCE, but the inconsistency meant an invalid segment (shell metacharacters, a--prefixed path) could still reach the scanner and trigger an unintended filesystem walk instead of a clean 400. This extracts the split/normalize/validate logic into a new_parse_model_dirs()helper that reuses_validate_local_dirso both endpoints enforce identical rules.Target branch
dev, notmain.Linked Issue
Fixes #5508
Type of Change
Checklist
devdocker compose uporuvicorn app:app) and verified the change works end-to-end. Type-checks and unit tests are not enough.How to Test
python -m pytest tests/test_cookbook_helpers.py— 73 passed (5 new tests added for_parse_model_dirs), 1 pre-existing skip.python -m pytest tests/ -k cookbook— 223 passed, 1 pre-existing skip, 1 unrelated pre-existing failure (confirmed viagit stashagainst unmodifieddev:test_container_opt_in_with_unix_socket_is_allowedfails withOSError: AF_UNIX path too long, a macOS pytest-tmp-path-length artifact in a Docker-socket test, nothing to do with this change).AUTH_ENABLED=false ODYSSEUS_DATA_DIR=/tmp/odysseus-data uvicorn app:app --host 127.0.0.1 --port 7001, then hit the real endpoint:curl "http://127.0.0.1:7001/api/model/cached?model_dir=/tmp/odysseus-data"→HTTP 200, real scan results returned.curl "http://127.0.0.1:7001/api/model/cached?model_dir=/tmp/x%3Btouch%20/tmp/pwned"(shell metacharacter) →HTTP 400,{"detail":"Invalid local_dir — must be an absolute or ~ path with no shell metacharacters"}— rejected before reaching the scan script.curl "http://127.0.0.1:7001/api/model/cached?model_dir=/models/-rf"(leading-dash segment / option injection) →HTTP 400,{"detail":"Invalid local_dir — path segments cannot start with '-'"}.curl "http://127.0.0.1:7001/api/model/cached?model_dir=/tmp/odysseus-data,/tmp/odysseus-data"(multi-segment) →HTTP 200, confirms comma-splitting still works for valid paths.python -m py_compile routes/cookbook_helpers.py routes/cookbook_routes.py— passes.Visual / UI changes — REQUIRED if you touched anything that renders
Not applicable — backend-only change (Python route handler + helper), no rendering code touched.