usestrix/strix · error · ValueError

Refusing to mount ' ' into the sandbox: ' ' holds…

Error message

Refusing to mount '{resolved}' into the sandbox: '{credential}' holds credentials, not code.

What it means

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.

Solutions

  1. Move the code out of any directory named like .ssh, .aws, .kube, .docker, .gnupg, .config, .azure into a normal project directory.
  2. If the name collides with a legitimate project dir, rename the component (e.g. 'ssh-studies' instead of '.ssh').
  3. Keep secrets outside the scanned tree and pass access via environment configuration instead of mounting.

Example fix

# before
strix -n -t ~/.config/my-app   # '.config' component refused

# after
mv ~/.config/my-app ~/projects/my-app
strix -n -t ~/projects/my-app
Defensive patterns

Strategy: validation

Validate before calling

FORBIDDEN_COMPONENTS = {".ssh", ".tsh", ".brev", ".gnupg", ".aws", ".azure",
                         ".kube", ".docker", ".config", ".git-credentials"}

def has_credential_component(path: str) -> bool:
    return any(part.casefold() in FORBIDDEN_COMPONENTS for part in Path(path).parts)

if has_credential_component(target):
    raise SystemExit(f"{target} sits inside a credential directory; move the project out")

Type guard

def is_free_of_credential_dirs(path: str) -> bool:
    return all(p.casefold() not in {".ssh", ".aws", ".kube", ".docker", ".gnupg", ".config", ".azure"} for p in Path(path).parts)

Try / catch

try:
    check_mountable_dir(Path(target))
except ValueError as e:
    if "holds credentials" in str(e):
        raise SystemExit("Rename/move the project out of the credential directory before scanning.") from e
    raise

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of usestrix/strix@8551339130 (2026-08-15). Data as JSON: /api/errors/04e53d6003fe3d2e. Report an issue: GitHub.

Appendix: source

Thrown at strix/interface/utils.py:1416

        tree_roots |= {str(drive / name) for name in _FORBIDDEN_WINDOWS_TREE_NAMES}
        exact.add(str(drive / "Users").casefold())
    trees = [Path(root) for root in tree_roots] + [Path(root).resolve() for root in tree_roots]
    if (
        str(resolved).casefold() in exact
        or resolved.parent == resolved
        or any(_is_within(resolved, tree) for tree in trees)
    ):
        raise ValueError(
            f"Refusing to mount '{resolved}' into the sandbox: it is a system "
            "or home directory, not a codebase. Point the target at the "
            "project directory you want tested."
        )

    credential = next(
        (part for part in resolved.parts if part.casefold() in _FORBIDDEN_MOUNT_DIR_NAMES), None
    )
    if credential is not None:
        raise ValueError(
            f"Refusing to mount '{resolved}' into the sandbox: '{credential}' "
            "holds credentials, not code."
        )


def dedupe_local_targets(targets_info: list[dict[str, Any]]) -> list[dict[str, Any]]:
    result: list[dict[str, Any]] = []
    seen_paths: set[str] = set()
    for target in targets_info:
        details = target.get("details") or {}
        path = details.get("target_path")
        if target.get("type") != "local_code" or not path:
            result.append(target)
            continue
        if path not in seen_paths:
            seen_paths.add(path)
            result.append(target)
    return result

View on GitHub (pinned to 8551339130)