Sandbox an AI coding agent: file and network limits via bubblewrap and Seatbelt
Let an AI coding agent run commands without approving each one, via an OS-level sandbox: file and network limits, defaults to know, and what it does not cover.
- An OS-level sandbox (bubblewrap on Linux, Seatbelt on macOS) lets the agent run commands on its own inside a boundary; Anthropic reports 84% fewer permission prompts in internal use
- You need both layers, filesystem and network; either one alone still leaks
- Claude Code's default lets sandboxed commands read most of the machine, ~/.ssh included; block secret files yourself
- The sandbox covers shell commands only; the Read/Edit tools, MCP servers and hooks run outside it
An AI coding agent that asks before every command trains people to click “yes” without reading, which is worse than not asking at all. Anthropic’s answer in Claude Code is an OS-level sandbox: the agent runs commands freely inside a file and network boundary you define, and asks only when it wants to step outside.
Facts checked against the Claude Code sandboxing docs, Anthropic’s engineering post (October 2025) and the sandbox-runtime README, as of October 2026. Setting names and defaults change between versions; check the docs for the version you run.
Why a sandbox beats approval prompts
Approval prompts rely on human attention, which runs out fast. A sandbox hands the decision to the operating system: inside the boundary, go ahead; outside it, the OS refuses, whether the agent was fooled by prompt injection or simply wrote a bad command.
Anthropic reports that in its internal usage, sandboxing reduced permission prompts by 84% (the post does not say how this was measured).
Worked example: what 84% means in a day
Suppose a session raises 100 approval prompts at 5 seconds each (assumed figures for the arithmetic):
- Without the sandbox: 100 × 5 = 500 seconds, about 8 minutes of babysitting
- With 84% fewer: 100 × (1 − 0.84) = 16 prompts
- Time spent: 16 × 5 = 80 seconds
More important than the time: the 16 that remain are the ones worth asking about, such as a new domain or a write outside the project, so people still have the attention to read them.
How it works
| System | Mechanism | Install |
|---|---|---|
| macOS | Seatbelt (built in) | Nothing |
| Linux and WSL2 | bubblewrap, separate namespaces including a network namespace | bubblewrap, socat |
| Native Windows | Claude Code runs commands unsandboxed | Use WSL2 |
Two layers work together:
- Filesystem. Commands can write only to the working directory, the per-user temp directory and directories you added. Claude Code’s own config files are write-protected even inside the working directory, because a command that could edit them could grant itself permissions or add a hook that runs outside the sandbox
- Network. Commands have no direct route out. Every connection goes through a proxy on your machine, outside the sandbox, which checks the hostname against your allowed domains. That list starts empty
The docs stress that both are needed. Without network isolation, a compromised agent can send files such as SSH keys out. Without filesystem isolation, it can modify system files to open a network path for itself.
Defaults you need to know
| Default | Change with | |
|---|---|---|
| Writes | Working dir, temp, added dirs | filesystem.allowWrite, filesystem.denyWrite |
| Reads | Most of the machine, including ~/.ssh and ~/.aws/credentials | filesystem.denyRead, credentials |
| Network | Through the proxy; allowed domains start empty | network.allowedDomains, network.deniedDomains |
| Environment | Inherited from Claude Code, secrets included | credentials, CLAUDE_CODE_SUBPROCESS_ENV_SCRUB |
Turning the sandbox on does not protect your secret files. By default commands can still read ~/.ssh; block it yourself.
Setup on Ubuntu or WSL2
Install the dependencies (Debian/Ubuntu, per the docs):
sudo apt-get install bubblewrap socat
Turn it on in a session with /sandbox; the panel also shows anything missing. Or put it in ~/.claude/settings.json:
{
"sandbox": {
"enabled": true,
"allowUnsandboxedCommands": false,
"filesystem": {
"denyRead": ["~/.ssh", "~/.aws", "~/.config/gcloud"]
},
"network": {
"allowedDomains": ["github.com", "*.npmjs.org", "registry.npmjs.org", "pypi.org", "files.pythonhosted.org"]
}
}
}
allowUnsandboxedCommands: falseremoves the escape hatch where a command that failed in the sandbox is retried outside it (normally via thedangerouslyDisableSandboxparameter, which then goes through the usual approval flow)denyReadstops shell commands reading keys and credentials- List only the domains the work actually needs
Check it works: have the agent run touch ~/sandbox-probe (what you type yourself after ! usually runs outside the sandbox, so it proves nothing). On Linux/WSL2 you should get Read-only file system; on macOS, Operation not permitted. If the touch succeeds, delete the file and open /sandbox to see whether it is really on.
What the sandbox does not cover
This is the most common misunderstanding. The sandbox wraps shell commands only (Bash, PowerShell, Monitor and their child processes). These run outside it:
- Built-in tools. Read, Edit, Write, WebFetch and WebSearch follow permission rules instead. A
denyReadentry does not stop the Read tool andallowedDomainsdoes not limit WebFetch; you need permission deny rules as well - Other processes Claude Code starts: hooks, local MCP servers, LSP servers and your status line command run with your full access
- Commands you type after
!in most sessions - Commands in
excludedCommands, and unsandboxed retries you approve
For one boundary around everything, run the whole agent in a container or VM, or use Anthropic’s open-source sandbox runtime (srt), which wraps any process, including other agents and MCP servers. As of October 2026 it is a beta research preview.
npm install -g @anthropic-ai/sandbox-runtime
srt "curl example.com" # blocked unless example.com is in ~/.srt-settings.json
srt "cat ~/.ssh/id_rsa" # Operation not permitted, when ~/.ssh is in denyRead
Security limits
- The proxy decides on the hostname and does not inspect TLS. Allowing a broad domain such as
github.comopens an exfiltration path, and the docs warn about domain fronting as a way around the allowlist - Unix sockets. Allowing
/var/run/docker.sockeffectively hands over the host (the Docker hardening article explains why that socket equals root) - Over-broad writes. Write access to
.bashrc,.zshrcor a directory on$PATHlets code run outside the sandbox the next time you open a shell enableWeakerNestedSandboxmakes it work inside Docker but weakens it considerably; use it only when another isolation layer surrounds it
Common mistakes
- Assuming keys are safe once the sandbox is on. Default reads include
~/.ssh. AdddenyReadorcredentials, and better still, keep production keys off the machine the agent works on - Putting
docker *in excludedCommands because docker fails in the sandbox. That gives the agent docker with your full rights; keep the pattern as narrow as possible - Allowing
*as a domain to stop the prompts. The whole network layer is gone - Testing by typing commands yourself. Commands after
!usually skip the sandbox, so the test lies - Running on native Windows and assuming you are protected. There is no sandbox there; use WSL2
- Forgetting that
npm installis a command too. Package install scripts run inside the sandbox, which is good; excluded, they run with your full rights. See the supply chain article
Sources
FAQ
Does it work on Windows?
On native Windows, Claude Code runs commands unsandboxed. For a sandbox, run Claude Code inside WSL2, which uses bubblewrap like Linux.
Why can't ssh or my database client connect even though the host is in allowedDomains?
The sandbox routes traffic through a proxy via HTTP_PROXY/HTTPS_PROXY. Tools that ignore those variables, such as plain ssh and most database drivers, cannot connect. UDP and ping cannot leave either.
With the sandbox on, is it safe to leave the agent running alone?
It cuts risk a lot, but the docs themselves say it is not a complete isolation boundary. For a boundary around the whole process, run the agent in a container, a VM or the sandbox runtime.
Commands and settings were tested on sample systems. Try them on a test machine before production.