{"record":{"id":"04e53d6003fe3d2e","repo":"usestrix/strix","slug":"refusing-to-mount-resolved-into-the-sandbox","errorCode":null,"errorMessage":"Refusing to mount '{resolved}' into the sandbox: '{credential}' holds credentials, not code.","messagePattern":"Refusing to mount '(.+?)' into the sandbox: '(.+?)' holds credentials, not code\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"strix/interface/utils.py","lineNumber":1416,"sourceCode":"        tree_roots |= {str(drive / name) for name in _FORBIDDEN_WINDOWS_TREE_NAMES}\n        exact.add(str(drive / \"Users\").casefold())\n    trees = [Path(root) for root in tree_roots] + [Path(root).resolve() for root in tree_roots]\n    if (\n        str(resolved).casefold() in exact\n        or resolved.parent == resolved\n        or any(_is_within(resolved, tree) for tree in trees)\n    ):\n        raise ValueError(\n            f\"Refusing to mount '{resolved}' into the sandbox: it is a system \"\n            \"or home directory, not a codebase. Point the target at the \"\n            \"project directory you want tested.\"\n        )\n\n    credential = next(\n        (part for part in resolved.parts if part.casefold() in _FORBIDDEN_MOUNT_DIR_NAMES), None\n    )\n    if credential is not None:\n        raise ValueError(\n            f\"Refusing to mount '{resolved}' into the sandbox: '{credential}' \"\n            \"holds credentials, not code.\"\n        )\n\n\ndef dedupe_local_targets(targets_info: list[dict[str, Any]]) -> list[dict[str, Any]]:\n    result: list[dict[str, Any]] = []\n    seen_paths: set[str] = set()\n    for target in targets_info:\n        details = target.get(\"details\") or {}\n        path = details.get(\"target_path\")\n        if target.get(\"type\") != \"local_code\" or not path:\n            result.append(target)\n            continue\n        if path not in seen_paths:\n            seen_paths.add(path)\n            result.append(target)\n    return result","sourceCodeStart":1398,"sourceCodeEnd":1434,"githubUrl":"https://github.com/usestrix/strix/blob/85513391305171ecc6faffe03da4a8bda5e3febb/strix/interface/utils.py#L1398-L1434","documentation":"The second half of the mount guard: even outside system trees, the path is rejected if ANY path component matches a credential-directory name (.ssh, .gnupg, .aws, .azure, .kube, .docker, .config, etc., case-insensitive). Mounting such directories would hand the sandboxed scanner the user's private keys and cloud credentials.","triggerScenarios":"A target path like ~/.ssh/project, /backups/.aws/credentials-workdir, or any project nested under a directory named .ssh/.aws/.kube/.docker/.gnupg/.config/.azure/.tsh/.brev; also case variants like /data/SSH/ or /data/.AWS/ (compared casefolded).","commonSituations":"Users creating scratch dirs inside dotfile dirs; repos checked out under ~/.config (some tooling does this); deliberately putting test fixtures under a folder named .ssh.","solutions":["Move the code out of any directory named like .ssh, .aws, .kube, .docker, .gnupg, .config, .azure into a normal project directory.","If the name collides with a legitimate project dir, rename the component (e.g. 'ssh-studies' instead of '.ssh').","Keep secrets outside the scanned tree and pass access via environment configuration instead of mounting."],"exampleFix":"# before\nstrix -n -t ~/.config/my-app   # '.config' component refused\n\n# after\nmv ~/.config/my-app ~/projects/my-app\nstrix -n -t ~/projects/my-app","handlingStrategy":"validation","validationCode":"FORBIDDEN_COMPONENTS = {\".ssh\", \".tsh\", \".brev\", \".gnupg\", \".aws\", \".azure\",\n                         \".kube\", \".docker\", \".config\", \".git-credentials\"}\n\ndef has_credential_component(path: str) -> bool:\n    return any(part.casefold() in FORBIDDEN_COMPONENTS for part in Path(path).parts)\n\nif has_credential_component(target):\n    raise SystemExit(f\"{target} sits inside a credential directory; move the project out\")","typeGuard":"def is_free_of_credential_dirs(path: str) -> bool:\n    return all(p.casefold() not in {\".ssh\", \".aws\", \".kube\", \".docker\", \".gnupg\", \".config\", \".azure\"} for p in Path(path).parts)","tryCatchPattern":"try:\n    check_mountable_dir(Path(target))\nexcept ValueError as e:\n    if \"holds credentials\" in str(e):\n        raise SystemExit(\"Rename/move the project out of the credential directory before scanning.\") from e\n    raise","preventionTips":["Never check out projects under ~/.config, ~/.ssh, or other dotfile credential dirs","Treat the mount refusal as a prompt to keep secrets out of scanned trees entirely"],"tags":["sandbox","security","credentials","filesystem","docker"],"backgroundTag":null,"analyzedSha":"85513391305171ecc6faffe03da4a8bda5e3febb","analyzedAt":"2026-08-15T05:03:57.275Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}