To sandbox an AI coding agent, run the commands it executes inside a boundary the operating system enforces: writes only inside the project, no network except the hosts it needs, and no access to your keys. Claude Code and Codex CLI have a sandbox built in that you turn on in settings. For any agent, including OpenCode, a container or VM with only the project mounted does the same job.
Permission rules decide what the agent may try. A sandbox decides what any attempt can reach, including a script the agent wrote and a package it installed.
Why permission rules aren’t enough
Three different threats, and any one of them is enough:
- The model makes mistakes, or gets talked into them. A web page or an issue comment it reads can carry instructions for it. A rule that blocks
rmdoesn’t stoppython -c "import shutil; ...". - The toolchain runs code nobody reviewed. In 2025 the Shai-Hulud worm spread through hundreds of npm packages. Its code ran from install scripts, harvested npm tokens, GitHub tokens and cloud credentials, and published itself further with them. CISA told affected developers to rotate everything. An agent that runs
npm installruns those scripts, as you, before it has thought about anything. - You hand over your whole account. An agent running in your shell can read whatever you can read:
~/.ssh,~/.aws,~/.npmrc, your environment variables. It only needs a network connection to send them somewhere.
No amount of careful prompting touches the second and third. Only a boundary does. That matters most the moment you let an agent run unattended, skip approvals, install packages or work on a repository you didn’t write.
Which sandbox does my agent have?
| Agent | Built-in sandbox | How to turn it on | Platforms |
|---|---|---|---|
| Claude Code | Yes, for shell commands | /sandbox, or "sandbox": { "enabled": true } in settings | macOS, Linux, WSL2. Not native Windows |
| Codex CLI | Yes | sandbox_mode = "workspace-write" in ~/.codex/config.toml | macOS, Linux, Windows |
| OpenCode | Not in its docs | Run it in a container (below) | Anywhere Docker runs |
Claude Code
Turn it on for every project in ~/.claude/settings.json:
{
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"filesystem": {
"denyRead": ["~/.ssh", "~/.aws", "~/.config/gcloud", "~/.npmrc"]
},
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"]
}
}
}
Commands may then write only in the project and a temp folder, and reach only the domains you list.
The read trap: by default the sandbox lets commands read most of your machine, including
~/.sshand~/.aws/credentials. It blocks writes and network, so stolen data can’t leave, but don’t rely on the network rule alone. Add your credential folders todenyRead, as above.
Two more things from Anthropic’s docs:
- It covers shell commands only. File tools, MCP servers and hooks run outside it, so keep permission rules for those.
failIfUnavailable: truemakes it fail closed. If the sandbox can’t start, Claude Code refuses to run instead of quietly running without one.
On native Windows, Claude Code runs commands unsandboxed. Run it in WSL2 to get the sandbox; see Claude Code on Windows.
Codex CLI
In ~/.codex/config.toml:
sandbox_mode = "workspace-write"
approval_policy = "on-request"
Codex can then edit and run commands in the project and temp folders, with no network unless you turn it on:
[sandbox_workspace_write]
network_access = true
Even in workspace-write, .git, .codex, .agents and .aws inside the project stay read-only, so the agent can’t rewrite its own config or your git history directly. Codex uses Seatbelt on macOS, bubblewrap with seccomp on Linux, and its own mechanism on Windows. danger-full-access turns all of this off.
Any agent: a container
A container with only the project mounted keeps your home folder, keys and other projects out of reach. OpenCode publishes an image:
docker run -it --rm -v "$PWD:/workspace" -w /workspace ghcr.io/anomalyco/opencode
In PowerShell, use ${PWD} instead of $PWD. The agent sees the project and nothing else from your machine.
- Mount only the project. Never
~/.ssh,~/.awsor your whole home folder. - Pass in one key, with
-e. Only the model provider’s API key, and preferably a key made just for this. - Limit the network if you can. The agent needs its model’s API; most other traffic it doesn’t.
For Claude Code, Anthropic maintains a dev container setup with an optional egress firewall.
A container makes it tempting to turn approvals off entirely, but Anthropic’s own docs warn that a dev container run with --dangerously-skip-permissions does not stop a malicious project from sending out anything inside the container, including Claude Code’s own credentials. Use it only with repositories you trust. What —dangerously-skip-permissions does covers what the flag turns off.
What makes a sandbox good?
Whichever tool you use, these rules separate a real boundary from a partial one:
- Fail closed. If the boundary can’t be built, the agent doesn’t start. A half-built wall is no wall.
- Treat the network as the crown jewel. Stolen credentials that can’t leave the box are harmless. Deny outbound traffic by default and name the hosts the agent truly needs, each with a reason.
- Be up before install time. Install scripts run before the agent reads a single prompt. A sandbox that only wraps the running agent has already lost.
- Keep the agent away from its own rules. If the agent can write to the file that defines its sandbox, it isn’t a sandbox.
- Log every refusal. A well-behaved agent never touches the wall. Anything that does is worth seeing.
Sandboxes that cut off the network without root build a private network namespace, which needs unprivileged user namespaces. Ubuntu 23.10 and 24.04 restrict those by default through AppArmor (kernel.apparmor_restrict_unprivileged_userns), so on a stock Ubuntu machine a network sandbox can refuse to start. The fix is either an AppArmor profile for the one tool, or relaxing the setting host-wide.
Contenox
On Windows, the Contenox desktop app runs the agent in a sandbox that limits writes to the project folder. Windows doesn’t let it restrict reads, so the permission rules that block SSH keys, cloud credentials and browser profiles still matter. Download Contenox.
How do I check that the sandbox works?
Don’t trust the setting; test it. First, outside the agent, put a harmless file where your keys live:
echo canary > ~/.ssh/sandbox-canary
Never test with a real key: if the sandbox isn’t working, the key would land in the model’s context. Then ask the agent to run these, one at a time, and confirm each one fails:
cat ~/.ssh/sandbox-canary
curl -sI https://example.com
touch ../outside-the-project.txt
- The first should fail if you blocked reading credentials. If it prints
canary, your read rules aren’t working, and a real key would have been readable too. - The second should fail unless
example.comis on your allowed list. If you get HTTP headers back, the network is open. - The third should fail because it writes outside the project.
Run them again after every change to the sandbox settings, and delete the canary file when you are done.
Related guides
- AI agent permissions: rules for what the agent may try
- Keep secrets away from AI agents: keys out of the project and out of reach
- YOLO mode: what each agent’s skip-approvals switch really turns off
- AI coding agents on Windows: which sandboxes work natively and which need WSL2
- Terminal coding agents: Claude Code, Codex CLI and OpenCode
- Git workflow with AI agents: undo anything the agent did inside the sandbox