Coding agent sandbox: what to isolate, and why

Stefan-Iulian Tesoi · · 7 min read

A black handwheel on the sealed round hatch of a stainless steel tank, condensation beaded inside the glass, everything in the vessel kept in until someone turns the wheel

Isolate three things: the file system outside the project, the network outside the few hosts the task needs, and every credential that reaches production. A container handles the first in an afternoon. The other two are where incidents come from, because an agent holding a live production credential can do whatever that credential allows, whatever its prompt says.

Most of the effort teams put into a coding agent sandbox goes into the container, which is the part that matters least. The container decides what the agent can see. The network and the credentials decide what it can do with what it sees.

What is a coding agent sandbox for?

It is what makes it safe to stop approving every command. A coding agent runs shell commands it wrote itself, from instructions that can include text written by a stranger in an issue. Permission prompts are the other control, and they fail by fatigue: by the fortieth npm test, nobody reads the forty-first prompt.

Anthropic's documentation for Claude Code puts the trade plainly: "With no prompts to catch mistakes, the isolation boundary you choose is what protects your system." Its own numbers show the size of the trade. In Anthropic's internal use, sandboxing cut permission prompts by 84%. Claude Code also refuses to start with --dangerously-skip-permissions when running as root, because an unattended run with nothing around it is the configuration the flag's name warns about.

A sandbox does not make an agent trustworthy. It makes a wrong agent cheap, which is the property worth paying for, and it is the same reasoning that settles what permissions a coding agent should have: judge the grant by the worst thing it allows.

File system, network, credentials: the three boundaries

Each boundary stops a different failure, and a sandbox that closes one leaves the other two exactly as open as before.

BoundaryWhat goes wrong without itCheapest controlWhat it still allows
File systemThe agent reads ~/.ssh, ~/.aws and every other repository on the machineA container that mounts only the projectRewriting anything in the project, .git/hooks included
Network egressAnything it reads can be sent anywhere; anything it fetches can runDefault-deny egress with an allowlistLeaks through the hosts on the allowlist
CredentialsA mistake lands on the production database or the cloud accountShort-lived tokens scoped to one task, held outside the agent's processEverything the scoped token covers

The defaults show which boundary gets the attention. Claude Code's sandboxed Bash tool, built on bubblewrap on Linux and Seatbelt on macOS, confines writes to the working directory and routes every connection through a proxy whose allowed domains start empty. Reads are another matter: by default it can read the whole computer except certain denied directories, and its documentation notes that this "still allows reading credential files". Credentials are the boundary you configure yourself.

Is a Docker container enough?

For the file system, mostly. For the network and credentials, a container changes nothing until it is configured to. A default Docker container on the bridge network reaches the whole internet, and it holds every environment variable it was started with.

To run Claude Code in Docker properly, start from Anthropic's reference dev container for AI agents, published in the anthropics/claude-code repository. It adds a default-deny firewall, init-firewall.sh, which needs the NET_ADMIN and NET_RAW capabilities to install its rules. The documentation is candid about the limit: under --dangerously-skip-permissions, a dev container does "not prevent a malicious project from exfiltrating anything accessible inside the container, including the Claude Code credentials". A container is a boundary around what is outside it. Whatever is inside is in reach.

The options, from lightest to strongest:

For code nobody has reviewed, such as a contributor's branch, Anthropic recommends a dedicated virtual machine. For a team's own repository, a container with a firewall is a reasonable floor.

Why does network egress matter more than it looks?

Because egress is the channel every other leak needs. An agent that can read a secret but cannot send it anywhere has a much smaller problem than one that can. Claude Code's guidance on sandbox environments says it directly: "Any approach that allows network egress can still leak data the agent can read."

AI agent network isolation means a short allowlist: the package registry, the Git host, the model API. Two caveats keep it honest. A domain allowlist is coarse, so allowing github.com allows pushing to any repository on it, an attacker's included. And a package install is code execution, since a postinstall script runs with the agent's permissions. Instructions planted in a ticket are what turn either caveat into an incident.

The other half is removing reasons to call out at all. Laimonade's own coding sandbox switches off web search and fetch, and the agent's only model endpoint is a proxy on the Laimonade backend, so no provider key sits in the sandbox. Each run gets its own Fly Machine, a Firecracker microVM created for the run and destroyed after it. The GitHub token lasts one hour, covers one repository and is held by a process running as a different user, so it never enters the agent's environment.

How do you give an agent realistic data without giving it production?

Give it data shaped like production that belongs to nobody: seeded fixtures, generated records, or a masked snapshot restored into a database the sandbox created and destroys with it. The test is the connection string, not the environment's name. Whatever the credentials reach is the environment.

The public example is Replit. In July 2025, during an explicit code freeze, its agent ran destructive commands against SaaStr's production database and wiped records for 1,206 executives. Replit's response was automatic separation of development and production databases. The freeze was an instruction. The separation is a control.

A database is production if a production credential opens it. What the environment is called does not enter into it.

We have a smaller example of our own. A server left over from a hosting migration had no inbound traffic, and it kept claiming scheduled jobs from the production database, because its configuration still held the production connection string. Nobody would have called it production. The database did.

In practice:

  1. Seed from fixtures in the repository, created when the sandbox starts.
  2. Mask before data leaves production, never after it arrives in the sandbox.
  3. Keep production connection strings out of every .env the agent can open. Keeping secrets away from coding agents covers the rest of that list.

The wider question of what a connection should be structurally unable to do is in coding agent security: what can it reach?. These boundaries are also the evidence a reviewer will ask for when getting security review approval for coding agents.

Frequently asked questions

Does sandboxing slow an agent down?

Less than permission prompts do. A container starts in seconds and a Firecracker microVM in under 125 ms, while every prompt waits for a person. The real cost is maintenance: a blocked domain fails a package install, and someone has to decide whether to add it. Budget for a short allowlist that grows on purpose, not one that is widened whenever a build fails.

Should the sandbox be thrown away after every task?

Yes, for unattended work. A disposable sandbox cannot carry a planted Git hook, a poisoned cache or a leftover token into the next task, which a long-lived one can. The cost is reinstalling dependencies each time. Bake them into the image rather than a volume the agent can write, so the speed-up does not reopen the hole.

Is running an agent in CI a form of sandboxing?

Partly. A CI runner is ephemeral, which handles cleanup, but it usually has open egress and every secret the workflow exposes, which are the two boundaries that matter most. Give the agent's job a token scoped to its own repository, and keep deploy credentials in a separate job its steps cannot reach.