AI dev workflow
M. Patel8 min read3 views

Claude Code Sandbox: What /sandbox Actually Locks Down (2026 Field Log)

A field log of Claude Code's built-in /sandbox: what its OS-level cage actually locks down, the setup that bit me, what auto-allow still stops for, the tools that broke, and the one thing it does not protect.

A Claude Code terminal inside a locked glass box with an amber isolation boundary and a padlock, representing the OS-level sandbox
A Claude Code terminal inside a locked glass box with an amber isolation boundary and a padlock, representing the OS-level sandbox
On this page

Quick answer (2026): Claude Code's built-in sandbox, opened with the /sandbox command, wraps every Bash command in OS-level isolation: Seatbelt on macOS, bubblewrap on Linux and WSL2. By default a sandboxed command can write only to your working directory and the session temp directory, and it prompts the first time it reaches a new network domain. In auto-allow mode most commands run without a permission prompt because the operating system boundary contains them. It genuinely cuts prompt fatigue. But it is not a hard isolation boundary: by default it still lets commands read ~/.aws/credentials and ~/.ssh, it does not inspect TLS, and it covers only Bash, not your file tools, MCP servers, or hooks. For unattended --dangerously-skip-permissions runs you still want a container or a VM.

I turned on the Anthropic logo Claude Code sandbox on a Tuesday because I was tired of hitting "yes" forty times an hour, and I ran it as my default for the rest of the week on two real projects. This is the field log: what /sandbox actually locks down, the two places it bit me on setup, the commands it still stops for, the four tools that broke inside it, and the one thing it does not protect that made me keep a VM around anyway.

Everything below is from Anthropic's own sandboxing docs cross-checked against what happened on my machine (macOS on the laptop, Ubuntu on the box). Versions move fast here, so treat the exact settings keys as current-as-of-July-2026 and check the docs if a field name has drifted.

What /sandbox actually is

Run /sandbox in a session and you get a panel with three tabs: Mode, Overrides, and Config (plus a Dependencies tab on Linux if something is missing). The mental model that finally made it click for me: this is not a permission mode. It is an OS-enforced cage around Bash. Two layers, and you can run either without the other.

Filesystem isolation. A sandboxed command gets read/write access to the current working directory and its subdirectories, plus the session temp directory that $TMPDIR points to. It can read most of the rest of the disk but cannot write outside those two roots, so it cannot touch ~/.bashrc, /bin, or (nicely) Claude Code's own settings.json files, which are write-denied at every scope automatically.

Network isolation. No domains are allowed by default. The first time a command needs a new host, you get one prompt; say yes and that host is allowed for the rest of the session. A proxy running outside the cage enforces the allowlist.

The enforcement is done by real OS primitives, so it applies to every child process a command spawns, not just to whatever Claude typed:

  • Apple logo
    macOS: Seatbelt, the built-in sandbox. Nothing to install.
  • Linux logo
    Linux and WSL2: bubblewrap for filesystem isolation, plus socat to relay traffic through the proxy. WSL1 is not supported; native Windows is not supported (run it inside WSL2).

The two places setup bit me

On macOS it was genuinely zero-install. On the Ubuntu box it was not, and both snags are worth knowing before you burn twenty minutes.

Missing packages. On a fresh Linux install the /sandbox panel showed only a Dependencies tab listing what was missing. Fix:

bash
sudo apt-get install bubblewrap socat

Ripgrep ships with the Claude Code binary already. The optional seccomp filter (it blocks Unix domain sockets) is a separate install: npm install -g @anthropic-ai/sandbox-runtime. The dependency check only runs at startup, so restart Claude Code after installing or the panel will keep insisting the packages are gone.

Ubuntu 24.04 AppArmor. On 24.04 and later, the default AppArmor policy blocks bubblewrap from creating the user namespaces it needs. The tell is sysctl kernel.apparmor_restrict_unprivileged_userns returning 1. The fix is a small AppArmor profile that grants bwrap the userns capability, then sudo systemctl reload apparmor. The docs spell out the exact profile; I mention it here only because the failure mode is silent-ish (the sandbox just refuses to start) and it cost me the most time of anything this week.

What auto-allow still stops for

This is the part I did not expect and the part that made me trust it. Auto-allow does not mean "run anything." Even with the sandbox auto-approving commands, these still interrupt you:

  • Explicit deny rules are always respected.
  • rm or rmdir targeting /, your home directory, or other critical system paths still triggers a prompt.
  • Content-scoped ask rules like Bash(git push *) still force a prompt, even for a sandboxed command.
  • A bare Bash (or Bash(*)) ask rule is skipped for sandboxed commands but still applies to anything that falls back to the normal permission flow.

So the model is: the cage handles the "could this trash my machine" question at the OS level, and your ask/deny rules still handle the "I specifically want to see this" cases. Pushing to git still stopped and asked me every time, which is exactly what I wanted.

When a command genuinely cannot run sandboxed, Claude analyzes the failure and may retry it with a dangerouslyDisableSandbox parameter, which runs it outside the cage through the regular permission flow (so you get a prompt). If you never want that escape hatch, set "allowUnsandboxedCommands": false, which the Overrides tab calls Strict sandbox mode.

The four things that broke inside the cage

Real friction from one week. None of it was a dealbreaker, but you will hit these:

  1. Jest hung. watchman is incompatible with the sandbox. jest --no-watchman fixed it instantly.
  2. Docker failed.
    Docker logo
    docker does not run sandboxed. Add docker * to excludedCommands so it runs outside.
  3. gh and Terraform failed TLS on macOS.
    Terraform logo
    Go-based CLIs (gh, gcloud, terraform) can fail TLS verification under Seatbelt. Listing them in excludedCommands was the clean fix.
  4. open threw error -600. The macOS sandbox blocks Apple Events by default, so open and osascript fail. There is an allowAppleEvents setting, but turning it on removes code-execution isolation, so I left it off and excluded the one script that needed it.

The pattern across all four: excludedCommands is your pressure valve. Keep the list short and specific rather than widening the whole policy.

The config I actually kept

By the end of the week I stopped selecting things in the panel (that just writes to .claude/settings.local.json per project) and moved a stable config into my user settings at ~/.claude/settings.json so every project inherits it. The two lines that matter most are the credential blocks, because the sandbox's default read policy still exposes your secrets:

json
{
  "sandbox": {
    "enabled": true,
    "credentials": {
      "files": [
        { "path": "~/.aws/credentials", "mode": "deny" },
        { "path": "~/.ssh", "mode": "deny" }
      ],
      "envVars": [
        { "name": "GITHUB_TOKEN", "mode": "deny" },
        { "name": "NPM_TOKEN", "mode": "deny" }
      ]
    },
    "network": {
      "allowedDomains": ["github.com", "registry.npmjs.org"]
    }
  }
}

sandbox.filesystem.allowWrite is the other one I reached for, to let kubectl and a build script write to ~/.kube and a scratch dir without excluding the whole tool. Those paths are enforced at the OS level, so a subprocess three layers deep respects them too.

What it does not protect (and why I kept a VM)

Here is the honest ceiling. The sandbox reduces risk; it is not a hard boundary, and Anthropic says so plainly.

  • It reads your credentials by default. The default read policy allows reading the entire computer minus a few denied dirs. That includes ~/.aws/credentials and ~/.ssh unless you add the credentials block above. This is the single most important thing to configure, and it is off by default.
  • It does not inspect TLS by default. The proxy makes its allow decision from the hostname the client hands it, without terminating TLS. Allow a broad domain like github.com and a determined process could use domain fronting to reach elsewhere. There is an experimental network.tlsTerminate, but out of the box, encrypted traffic is not examined.
  • It only cages Bash. Your built-in Read/Edit/Write tools, your MCP servers, and your hooks all still run unconstrained on the host. If you want those inside a boundary too, you need the whole-process sandbox runtime (npx @anthropic-ai/sandbox-runtime claude, still beta), a dev container, or a VM.

Which is why, for anything I run with --dangerously-skip-permissions or point at a repo I do not trust, I still use a container or a throwaway VM. The Bash sandbox is the right tool for the everyday case: I am at the keyboard, I trust the code, and I just want fewer prompts. It is the wrong tool as your only line of defense for unattended runs. If you are still hand-approving everything, the honest upgrade path is the sandbox first, then a container when you actually walk away from the machine. My notes on trimming prompts the manual way live in the claude-code-permissions-field-log-2026 log, and the sandbox config carries into claude-code-subagents-field-log-2026 since subagents inherit the parent session's cage.

Verdict after a week

I kept it on. Auto-allow plus the credential-deny block plus a three-line excludedCommands list turned a session from a permission-prompt slot machine into something that mostly just runs, while the destructive-command and git push prompts I actually care about still fire. Budget half an hour for Linux setup, add the credential block on day one, and do not mistake it for the thing that lets Claude run unattended. For that, you are still building a real cage, not borrowing this one.

Sources

M

Written by

M. Patel

Frequently asked questions

Is the Claude Code sandbox on by default?

No. It is opt-in. Turn it on per project by running /sandbox and choosing a mode, or across all projects by setting sandbox.enabled to true in ~/.claude/settings.json.

Does the sandbox work on Windows?

Not natively. It runs on macOS, Linux, and WSL2. On a Windows host, run Claude Code inside a WSL2 distribution, or use a container or VM. WSL1 is not supported.

Does auto-allow mean Claude can run anything without asking?

No. Explicit deny rules, rm/rmdir against critical paths like / or your home directory, and content-scoped ask rules such as Bash(git push *) still prompt even in auto-allow mode. The sandbox contains ordinary commands; it does not switch off your ask and deny rules.

Can a sandboxed command still read my AWS or SSH keys?

By default, yes. The sandbox's default read policy allows reading most of the disk, including ~/.aws/credentials and ~/.ssh. Block them with a sandbox.credentials.files deny block (and unset or mask secret environment variables) if that matters to you.

Is the Bash sandbox enough to run Claude Code unattended?

No. It only isolates Bash subprocesses, not file tools, MCP servers, or hooks, and it does not inspect TLS by default. For --dangerously-skip-permissions or untrusted code, use the whole-process sandbox runtime, a dev container, or a VM.