fix(resume): re-validate persisted mounts with the mount guard - #1216
Open
LuckVd wants to merge 2 commits into
Open
fix(resume): re-validate persisted mounts with the mount guard#1216LuckVd wants to merge 2 commits into
LuckVd wants to merge 2 commits into
Conversation
added 2 commits
September 1, 2026 13:47
test_resolves_common_bare_model_names asserted against LiteLLM's mutable model-cost registry, so it passed or failed depending on whether LiteLLM's remote model cost map (multiple differently priced MiniMax-M3 routes) or the local fallback (single route) was loaded at runtime. Mock a small fixed registry, matching the pattern already used by the other resolver tests, so the assertions never depend on external registry state.
--resume rebuilt sandbox bind mounts from run.json but skipped check_mountable_dir for workspace_mount and repository cloned_repo_path (local_code paths were already re-checked), and workspace_files sources were not guarded at all. run.json lives on disk under the scanned tree and must be treated as untrusted: a tampered record could mount '/' or $HOME writable, or copy credential files into the sandbox. Apply the same guard on resume: - workspace_mount and cloned_repo_path now pass through check_mountable_dir - workspace_files sources pass through the new check_mountable_file, which applies the same system/home/credential checks to a single file - split the shared root/tree/credential sets into _mount_guard_sets used by both guards Adds unit coverage for check_mountable_file and resume integration tests for the three bypass paths.
Contributor
Greptile SummaryThe PR closes resume-time mount-validation gaps for persisted repository paths, workspace mounts, and workspace files.
Confidence Score: 5/5The PR appears safe to merge, with persisted sandbox inputs consistently revalidated before resume. The new validations cover the previously unchecked persisted mount sources, resolve symlinks before policy checks, preserve clean resume behavior, and introduce no supported changed-code failure. Important Files Changed
Reviews (1): Last reviewed commit: "fix(resume): re-validate persisted mount..." | 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.
Description
Fixes #1214
--resumerebuilt sandbox bind mounts fromstrix_runs/<run>/run.jsonbut did not applycheck_mountable_dirtoworkspace_mountor a repository target'scloned_repo_path(onlylocal_codetargets were re-checked), andworkspace_filessources were not guarded at all. run.json lives on disk under the scanned tree and can be tampered with (e.g. by prompt-injected sandbox agent output during a whitebox scan of the project itself), so a modified record could mount/,$HOMEor.sshwritable into the next resumed sandbox, or copy credential/system files in viaworkspace_files[].source_path. A comment in the resume path even documented the guard as intentionally skipped forworkspace_mount.Change
strix/interface/cli_args.py(_load_resume_state):workspace_mountnow passes throughcheck_mountable_dirafter the existence check, beforeattach_workspace_mount.cloned_repo_pathnow passes throughcheck_mountable_dirafter the existence check (missing-directory guidance preserved).workspace_filessources restored from the record are each passed through the newcheck_mountable_filebeforeresolve_workspace_files; a tampered record can no longer smuggle credential/system files into the sandbox.strix/interface/utils.py:check_mountable_file(path): applies the same system/home/credential checks ascheck_mountable_dir, evaluated against the file's parent directory and its own path components._mount_guard_sets(anchor)used by both guards (no behavior change forcheck_mountable_dir).tests/test_local_sources.py: 6 newcheck_mountable_filecases (project file accepted; missing/system/home/credential files rejected; project file under the home root accepted).tests/test_cli_resume.py(new): resume integration tests — forbiddenworkspace_mount(home), systemworkspace_mount(/etc), forbiddencloned_repo_path(/etc), credentialworkspace_filessource (~/.ssh/id_rsa) all abort; a clean record still loads.Scope note
The issue also suggests keeping run records outside any bind-mounted tree or making them immutable from inside the sandbox. That is a broader design change (run layout / sandbox writability) and is intentionally left out of this PR; the mount guard now covers all resume mount inputs regardless of where run.json lives, which closes the demonstrated bypass.
Ruff reports one pre-existing
ISC004(implicit string concatenation) onstrix/interface/utils.py:877— untouched by this change (confirmed present on the unmodified checkout) and not part of this diff.Type of Change
Related Issue
Testing
uv run pytest tests/test_local_sources.py tests/test_cli_resume.py tests/test_pricing.py -q— 45 passed (includes 6 new file-guard unit tests and 5 new resume integration tests).ruff checkon the four changed files — clean (only the pre-existingISC004on an untouched line remains inutils.py).ruff format --checkon changed files — clean.git diff --check— clean.Checklist
git diff --check origin/main...HEADpasses