An agent sandbox is mostly about what can leave it

More agents now write and run code as part of their work. A coding agent runs the test suite and installs packages. An analysis agent writes a script to reshape a spreadsheet and executes it. A browsing agent loads whatever the page loads. At that point the agent is no longer a caller of a few typed tools. It is a general-purpose computer with a model at the keyboard, and only the environment around it sets the limits.

The usual first response is to put the process in a container and consider the matter closed. Isolating the process is the easy half. The half that decides how bad a bad day gets is what sits inside the box with the agent, and what can leave it.

How agents get out without escaping

Breaking out of a container is rare and hard. Most of the damage is done by an agent doing something perfectly permitted inside the box, with consequences outside it.

Keys lying around. Cloud credentials in environment variables, a developer’s token in a configuration file, a cloud metadata endpoint that hands the machine’s role to any process that asks. The agent did not escape; it found keys.

An open network. Code that can reach any address can send anything anywhere: a request to an attacker’s server, data encoded into DNS lookups, a file pushed to a public repository or package registry.

Dependencies nobody chose. The agent installs a package mentioned in a README it has just read, or one with a plausible name that the model suggested and nobody checked. Installing a package runs someone else’s code.

State that outlives the task. A sandbox reused across tasks carries a modified configuration or a planted script from a poisoned task into the next, clean one.

The layers that matter

Infographic

Layers of an agent sandbox

  1. 01Disposable runtimeFresh for each task, destroyed afterwards. Nothing carries over.
  2. 02No secrets insideCredentials stay with tools outside the box that check each request.
  3. 03Scoped filesystemOnly the files the task needs, read-only where possible.
  4. 04Default-deny egressNamed destinations only, through a proxy that logs every request.
  5. 05Resource limitsCaps on time, memory and processes, so runaway work ends itself.
The process boundary is the easy part. The value is in what crosses it.

Disposable by default. A fresh environment for each task, destroyed when the task ends. Whatever a manipulated task changed disappears with it, and every task starts from a known state.

Nothing worth stealing inside. No credentials in the box. When the agent needs to act on something outside — push a branch, open a pull request, call an internal API — it asks a tool that runs outside the sandbox, holds the credential and checks the request. The code inside asks; the code outside decides.

Only the files the task needs. Mounted read-only where possible, with a separate place for outputs that something else inspects before they go anywhere.

Limits on time and resources. A runaway loop or an expensive mistake ends on its own, rather than at the end of the month on the invoice.

Browsers in a box of their own. A browsing agent opens untrusted code and untrusted text with every page, so it belongs in the most restricted environment you have, kept apart from anything that holds data.

Egress is the control that does the most

With no credentials inside and a network that denies by default, most of what a manipulated or confused agent can do stays in a box that is deleted within the hour. That makes egress the single most valuable control, and also the one most often left open because something needed the internet once.

Make it default-deny, with named destinations reached through a proxy that logs every request. Serve packages from an internal mirror with an approved set, not straight from public registries. Resolve DNS through a resolver you control, because DNS lookups can carry data out even when every other route is closed. And treat every exception as what it is: a firewall rule, with an owner and a reason.

The friction is the information

This setup creates friction. Tasks fail because a destination is not on the list, and teams ask for exceptions. That friction is useful. The list of exceptions becomes the first accurate map of what your agents actually reach, and nobody had that map before. Review it regularly: an exception nobody has used for months is removed, and one used constantly is a sign the task has grown beyond what was designed.

Coding agents are the agents most often handed a shell, and in a pipeline built for AI agents spec-driven development they run inside your CI, close to your repositories and deployment credentials. Where that box sits and what can leave it is one of the guardrails worth agreeing before the first generated change runs.