The Claude Code Sandbox: Limit What Shell Commands Can Touch
Claude Code's built-in sandbox wraps the shell commands Claude runs in an OS-enforced boundary: writes limited to your project, network only to allowed domains. How to turn it on, auto-allow mode, allowWrite, denyRead, allowedDomains, excludedCommands, credential masking, and what runs outside it.
Permission prompts protect you by asking before Claude runs a command. The sandbox protects you differently: it lets commands run, but inside a boundary the operating system enforces — so even a command you approved (or that was auto-approved) can't write outside your project or talk to hosts you didn't allow. (Claude Code permission modes)
It's built on Anthropic's open-source @anthropic-ai/sandbox-runtime: Apple's Seatbelt on macOS, bubblewrap plus a network proxy on Linux and WSL2. Native Windows runs commands unsandboxed — use WSL2. (What is WSL?, Bubblewrap)
Turning it on
It's off by default. In a session:
/sandbox
The panel shows missing dependencies (on Linux: sudo apt-get install bubblewrap socat), lets you pick a mode, and whether failed commands may retry unsandboxed. Or in settings:
{
"sandbox": { "enabled": true }
}
What it restricts by default
| Access | Default |
|---|---|
| Writes | Working directory, a per-user temp directory, added directories; protected paths stay write-denied |
| Reads | Most of the machine — including ~/.ssh and ~/.aws/credentials unless you deny them |
| Network | No direct route out; traffic goes through a local proxy that checks each host against your allowed domains (empty to start) |
| Environment | Inherited, including secrets — unless you mask them |
Note the read default: it's permissive. Tighten it if you care about credentials.
Check it's working by asking Claude to run touch ~/sandbox-probe — it should fail with Operation not permitted (macOS) or Read-only file system (Linux). Decline any offer to retry unsandboxed.
Two modes
- Auto-allow — commands running inside the sandbox are approved without a prompt. Deny rules, content-scoped ask rules like
Bash(git push *), andrmon critical paths still apply. This is the big productivity win: fewer prompts, with an OS boundary instead. - Regular permissions — the same boundary, but commands still go through normal approval.
Configuring the boundary
{
"sandbox": {
"enabled": true,
"filesystem": {
"allowWrite": ["~/.kube", "/tmp/build"],
"denyRead": ["~/.ssh", "~/.aws", "~/**/.env"]
},
"network": {
"allowedDomains": ["github.com", "*.npmjs.org", "registry.npmjs.org", "pypi.org"]
}
}
}
allowWrite— extra places tools legitimately write (kube config, build caches).denyRead/allowRead— block reads; a narrower allow can reopen part of a denied region, while a deny inside a broad allow still holds.allowedDomains— the only hosts sandboxed commands may reach. Package registries and your Git host are the usual minimum. Your permission mode decides what happens for other hosts.
Tools that don't work sandboxed
Docker, some build tools and anything needing privileged access can fail. Options:
{ "sandbox": { "excludedCommands": ["docker compose *"] } }
Excluded commands run outside the sandbox through normal permissions. Every command in a chained call must match, and the pattern matches the command text — a script that calls docker internally doesn't match.
There's also an unsandboxed retry: after a failure, Claude can ask to rerun a command outside the sandbox. For unattended runs, turn it off with "allowUnsandboxedCommands": false (strict mode).
Protecting credentials
Commands inherit Claude Code's environment, including tokens. The credentials setting can mask variables so commands see a placeholder, injecting the real value only for requests to specific hosts:
{
"sandbox": {
"credentials": {
"envVars": [
{ "name": "GH_TOKEN", "mode": "mask", "injectHosts": ["api.github.com"] }
]
}
}
}
A prompt-injected command that tries to send $GH_TOKEN elsewhere gets nothing useful. (Egress control for AI agents)
What runs outside the sandbox
Important limits:
- Claude's built-in file tools (Read, Edit, Write) and WebFetch follow permission rules, not the sandbox. A
denyReaddoesn't stop the Read tool — add a permission deny rule too. - Hooks, local MCP servers, your status line command run with your full access.
- Commands you type with
!usually run unsandboxed.
To put everything behind one boundary, run Claude Code itself inside a container or VM. (Claude Code in a dev container, Run AI-generated code safely)
When to use it
- Working in unfamiliar or third-party repositories.
- Long autonomous runs where you won't approve every command. (Running Claude Code unattended)
- Any time the agent reads untrusted content (issues, web pages) that might contain injected instructions. (Prompt injection)
EasySpawn adds the outer boundary: Claude Code runs on its own VM, so even what falls outside the sandbox can't reach your laptop, your other projects or anyone else's servers. See how it works or join the waitlist.
Related: Claude Code Permission Modes · Egress Control for AI Agents · Running Claude Code Unattended · The Sandbox Is the Wrong Abstraction
Keep reading
Claude Code --dangerously-skip-permissions: When It's Safe, and What to Use Instead
An agent that stops to ask permission can't work while you're away. An agent that never asks can delete things. How Claude Code's permission modes and allow/deny rules work, when skipping prompts is reasonable, and what has to be true of the environment first.
Running Claude Code in a Dev Container
Put Claude Code inside a dev container so every command it runs happens in an isolated, reproducible environment instead of on your machine. Adding the official Dev Container Feature, persisting login across rebuilds, enforcing policy with managed settings, restricting network egress, and the limits of the protection.