Skip to content
ARTICLES
MenuClose
Claude

Claude Code security in 2026: sandbox ladder, credentials, and when /sandbox is not enough

AUTHOR
Bartłomiej Krupa
PUBLISHED
2026.07.17
READ_TIME
10 min

The more permission dialogs you click through, the less you read them. Claude Code’s OS-level Bash sandbox (filesystem isolation plus network isolation) cut those prompts by about 84% in Anthropic’s internal usage, and it keeps a prompt-injected agent inside boundaries the kernel enforces. Mid-2026 added sandbox.credentials, managed lockdown keys, and a documented isolation ladder. One catch still trips people: /sandbox wraps Bash only. Read, Edit, MCP, and hooks stay on the host until you climb that ladder.

Definitions

Permission rules - allow / ask / deny checks that decide whether a tool may run at all (Bash, Read, Edit, WebFetch, MCP, and others). Evaluated before the tool runs. See the tools inventory and ToolName(specifier) rules.

Bash sandbox (/sandbox) - OS-level filesystem and network restrictions on Bash commands and every child process they spawn. Seatbelt on macOS; bubblewrap on Linux and WSL2. Native Windows is unsupported; use WSL2 or a container.

Sandbox runtime - @anthropic-ai/sandbox-runtime, which wraps the entire Claude Code process (file tools, MCP, hooks) in the same Seatbelt/bubblewrap primitives.

MCP - Model Context Protocol; the standard for third-party tool servers the agent can call. Each server is code you run alongside Claude Code.

Approval fatigue - rubber-stamping dialogs until they stop being a control and become noise. Sandboxing replaces per-command “may I?” with boundaries you declare once.

Why prompts are not enough

Claude Code starts read-only. Safe commands such as ls, cat, and git status run without a prompt; most mutating Bash still needs approval. Fine as a default. Broken as your only control after fifty approvals in an hour.

Prompt injection makes the gap concrete. Malicious text in a README, a fetched page, or a dependency can steer the agent toward curl, credential reads, or shell-config writes. Claude Code mitigates some of that: it sanitizes input, never auto-approves network commands, keeps WebFetch results in an isolated context, and asks about (rather than runs) any command its rules do not match. No model is injection-proof. The useful question is: if the agent is compromised, what can it still touch?

Anthropic’s answer is two boundaries that must both hold:

BoundaryWhat it stops
Filesystem isolationWriting outside the allowed paths (e.g. ~/.bashrc, system binaries); with credentials / denyRead, also reading secrets
Network isolationConnecting to hosts outside the domain allowlist (exfiltration, malware download)

Skip network isolation and an agent that can still read ~/.ssh can ship the keys out. Skip filesystem isolation and it can backdoor a tool that later gets network access. You need both.

The isolation ladder (2026)

Match the threat to the boundary. Climb when you skip prompts or touch untrusted code.

ApproachWhat is isolatedWhen to use it
Sandboxed Bash (/sandbox)Bash + children onlyEveryday local work; fewer prompts inside a known repo
@anthropic-ai/sandbox-runtimeWhole Claude process (tools, MCP, hooks)Unattended runs without Docker; MCP you do not fully trust
Dev container / custom containerFull development environmentTeam standard; --dangerously-skip-permissions with firewall allowlist
Virtual machineFull OS / kernel separationUntrusted repos; compliance needs strong separation
Claude Code on the webAnthropic-managed VM; Git via scoped proxyNo local setup; clone from GitHub in an isolated cloud VM

--dangerously-skip-permissions and long auto-mode sessions remove the human gate. Anthropic’s guidance: put those sessions in a container, a VM, or the sandbox runtime. Bash sandbox alone is not that boundary. Plan mode’s “read-only” promise is behavioral, not sandboxed. OS isolation is the hard layer.

Scope gap that bites

MechanismCovers Bash childrenCovers Read / EditCovers MCP / hooks
Permission rulesPattern-matched onlyYesYes (per tool)
/sandboxYes (OS-enforced)NoNo
Sandbox runtime / container / VMYesYes (inside boundary)Yes

Claude Code recognizes common file commands inside Bash (cat, sed, grep) and applies your Read/Edit deny rules to them too. A Python one-liner that opens ~/.ssh/id_rsa is not recognized, so it walks past those rules. OS sandbox plus sandbox.credentials closes that hole for Bash; permission denies close it for the Read tool. Set both.

Enable and configure /sandbox

/sandbox

Pick auto-allow (sandboxed Bash runs without prompts; out-of-bound access falls back to the normal permission flow) or regular permissions (isolation stays, every command still asks). On Linux/WSL2 install bubblewrap and socat first. macOS uses Seatbelt with nothing extra. WSL1 and native Windows are unsupported.

Defaults that matter:

  • Write: working directory + session $TMPDIR only
  • Read: nearly the whole machine, including credential files, unless you deny them
  • Network: no domains pre-allowed; the first time a command needs a new host, Claude Code prompts (from v2.1.191, approving keeps that host for the rest of the session)
  • Escape hatch: on sandbox failure Claude may retry with dangerouslyDisableSandbox (still goes through permissions). Set allowUnsandboxedCommands: false for strict mode

Project-local mode lands in .claude/settings.local.json (not committed). User-wide: sandbox.enabled: true in ~/.claude/settings.json. Orgs use managed settings.

Close the credential hole (v2.1.187+)

Default read policy was the quiet failure mode through early 2026: writes locked, reads wide open. sandbox.credentials groups file denies and env scrubbing. Deny entries merge across scopes - project, user, and managed; a project or user scope cannot loosen a deny that managed settings set.

{
  "sandbox": {
    "enabled": true,
    "failIfUnavailable": true,
    "allowUnsandboxedCommands": false,
    "filesystem": {
      "denyRead": ["~/"],
      "allowRead": ["."]
    },
    "credentials": {
      "files": [
        { "path": "~/.aws/credentials", "mode": "deny" },
        { "path": "~/.ssh", "mode": "deny" }
      ],
      "envVars": [
        { "name": "GITHUB_TOKEN", "mode": "deny" },
        { "name": "NPM_TOKEN", "mode": "deny" }
      ]
    },
    "network": {
      "allowedDomains": ["registry.npmjs.org", "api.github.com"]
    }
  },
  "permissions": {
    "deny": ["Read(~/.ssh/**)", "Read(~/.aws/**)", "Read(./.env*)"]
  }
}

Notes:

  • There is no built-in credential deny list. Empty credentials protects nothing.
  • mask (v2.1.199+) substitutes a sentinel inside the sandbox and injects the real secret only on listed injectHosts. It requires network.tlsTerminate. Mask entries in project settings are ignored; use user, managed, or CLI settings.
  • Broad allowlists like github.com still leave room for domain fronting - smuggling traffic to a blocked host behind an allowed hostname. The default proxy only checks the hostname the client claims; it does not look inside the encrypted traffic. If you need content inspection, terminate TLS at a custom proxy.
  • Never allow /var/run/docker.sock through allowUnixSockets. That is host access via Docker.

To scrub Anthropic and cloud-provider credentials from the environment of every subprocess (sandboxed or not), set CLAUDE_CODE_SUBPROCESS_ENV_SCRUB.

Org lockdown

Managed settings can require the sandbox and refuse soft fallback:

KeyEffect
sandbox.enabled: trueSandbox on for every developer
failIfUnavailable: trueMissing bubblewrap / unsupported platform → hard fail, not warn-and-continue
allowUnsandboxedCommands: falseIgnores dangerouslyDisableSandbox retries
allowManagedDomainsOnlyOnly managed domain allowlists apply
allowManagedReadPathsOnlyDevelopers cannot widen allowRead locally

excludedCommands still merges from every scope, so a developer can always append tools that run outside the sandbox. Keep the managed list narrow (docker * is a common necessary exception).

Cloud sessions add another tier. Each Claude Code on the web run is an Anthropic-managed VM with network controls, a Git proxy that keeps real tokens outside the sandbox, branch-restricted push, audit logs, and automatic cleanup. Remote Control - the phone/web UI that drives Claude Code on your own machine - is different: it talks to a local process, with no cloud VM and no Anthropic-managed sandbox.

What still sits outside the sandbox

Treat these as product limits, not bugs:

  • MCP servers. Put them on allowlists. Anthropic does not security-audit third-party servers. Prefer servers you wrote or trust; gate them with permission rules.
  • /security-review and PR review actions. Useful first pass. Outside evaluations (including Semgrep’s) find inconsistency and blind spots on multi-file and business-logic issues. Pair with deterministic static and dynamic analysis (SAST/DAST) tools.
  • Windows WebDAV. Avoid enabling WebDAV or \\* paths; they can trigger remote requests that bypass the permission system.
  • Home-directory trust. Claude Code asks you to trust a folder before working in it. Starting in ~ extends that trust to everything under your home directory for the session - that trust resets the next time you launch Claude Code. Start from a project subdirectory instead.
  • Data plane. Isolation does not change what is sent to the model API. Sandbox controls local blast radius, not training or privacy policy.

Practical playbook

  1. Trusted personal repo, interactive: /sandbox auto-allow + credential denies + narrow allowedDomains
  2. Team laptop fleet: managed enabled + failIfUnavailable + allowUnsandboxedCommands: false + sandbox.credentials for AWS/SSH/tokens
  3. Unattended / skip-permissions: container, VM, or npx @anthropic-ai/sandbox-runtime claude with write/network allowlists that include the project, ~/.claude, and api.anthropic.com
  4. Untrusted repository: dedicated VM or Claude Code on the web; do not rely on Bash sandbox alone
  5. Always: review suggested commands; deny curl/wget if your threat model requires it; audit with /permissions; keep SAST in CI

Slash commands for the control surface: /sandbox and /permissions. Details in the commands cheatsheet.

Bottom line

Permission rules decide whether a tool runs. The Bash sandbox decides what a running shell can touch. Containers and VMs decide whether the whole agent (including Read and MCP) shares your host. Turn on /sandbox, deny credential reads, and climb the ladder the moment you remove the human from the approval loop.

FAQ

Does Claude Code /sandbox isolate the Read tool and MCP servers?
No. The built-in Bash sandbox restricts only Bash commands and their child processes at the OS level (Seatbelt on macOS, bubblewrap on Linux/WSL2). Built-in file tools, MCP servers, and hooks still run on the host. To put those inside the boundary too, run Claude Code through @anthropic-ai/sandbox-runtime, a container, a VM, or Claude Code on the web.
Why can sandboxed Claude Code commands still read ~/.ssh or AWS credentials?
Default sandbox write access is the working directory plus the session temp directory, but default read access covers nearly the whole machine - including ~/.aws/credentials and ~/.ssh/. Deny those paths with sandbox.credentials (Claude Code v2.1.187+) or sandbox.filesystem.denyRead, and mirror sensitive paths in permissions.deny for the Read tool.
When is --dangerously-skip-permissions safe with Claude Code?
Only when the whole process sits inside an isolation boundary that also covers file tools and MCP - a container, a VM, or @anthropic-ai/sandbox-runtime. The built-in /sandbox alone is not enough for unattended runs, because Read, Edit, and MCP still execute on the host.