AI Development

Agent Sandboxes: The Boundary Is the Credential, Not the Container

Ask a team whether their agent is sandboxed and you'll get the name of a container runtime. That answers a different question. What decides your blast radius is which credentials exist inside the box, which hosts it can reach, and what it's allowed to carry back out.

KAKabir AnandLead Developer
10 min read
Flat vector illustration of a sealed workshop with a small pass-through hatch, connected to an outer room holding a key cabinet

The support-triage agent started with one tool: read the last 200 lines of a log file. Six weeks later it had a shell, because reading logs became grepping logs, and grepping became "just run the query yourself." Nobody ever made a decision to hand model-generated code a production database URL. It arrived one convenience at a time, and we only found it because the client had asked us to review something else entirely.

That is the shape of almost every agent-security problem we've been called into this year. Not a clever prompt injection — an execution environment that grew capabilities faster than anyone redrew its boundary. And the tooling has made this easier to do by accident, not harder: when the Agents SDK shipped native sandbox execution and portable workspace manifests in April, running untrusted code went from a weekend of Docker plumbing to a config block. The prototype pattern now reaches production intact, because nothing about it feels dangerous anymore.

The container is not the boundary

"It runs in a container" is the answer we get most often, and it answers a question nobody asked. A container limits what a process can do to the host. It says nothing about what that process can do with the credentials it was handed, or which hosts it can open a socket to. If a long-lived production token lives inside the sandbox, containment has bought you exactly one thing: whoever steers that code has to use your API instead of your filesystem. They were going to use the API anyway.

So we stopped drawing the boundary at the runtime and started drawing it at three places. A container is not any of them — it's the thing that makes the three enforceable.

  • Identity— which credentials exist inside the box at the moment the code runs. Our rule is absolute, and it is the only absolute rule we have here: the correct number of long-lived production secrets inside an execution sandbox is zero. Not “encrypted”, not “read-only”. Zero.
  • Reachability — every host the code can open a socket to. Default-deny, allowlisted per job. Most teams get identity roughly right and leave this wide open, which quietly hands back everything identity was protecting.
  • Return path— what comes back out, and what happens to it next. Sandbox output usually re-enters the prompt, so the boundary isn’t only about damage inside the box; it’s about text the box produced becoming instructions the control plane acts on.

Where the boundary actually sits

TRUSTED CONTROL PLANEUNTRUSTED SANDBOXSecret storelong-lived credsToken brokerscope + TTLEgress proxydefault denyScan + reviewpatch, not pushtrust boundaryephemeralModel-generated codeassume hostile/workcopied in, no host FSoverlaywrites leave as a diffno long-lived secrets in herescoped token, 15 minevery socketresults come back as data, never as trust
The sandbox holds no durable identity of its own. It borrows a narrow one for a few minutes, and every socket it opens is somebody else's decision.

Broker, proxy, hatch

Four projects in, the architecture has converged on three components. None of them is exotic and all three are boring to operate, which is the point — the failure we are designing against is a tired engineer at 11pm, not a nation state.

  • The broker issues capabilities, not credentials — the sandbox never asks for a connection string. It asks for “read invoices for tenant 4182”, and gets back a token scoped to exactly that, expiring in fifteen minutes. The most useful effect is on design rather than security: the moment you have to name the capability, you find out how many of your agent’s tools were really asking for “the whole database, please.”
  • The proxy is default-deny and per-job— the allowlist gets written when the job is defined, not when it fails. Hosts and methods, TLS terminated so the log is readable, and in practice four to six entries. If your allowlist has grown past a dozen, you don’t have a policy, you have a changelog of everything that broke.
  • The hatch copies in and copies out — no bind mounts to the host. Inputs are copied into the work directory at start; writes land on an overlay and come back as a patch that a human or a CI check applies. It costs a couple of seconds a run and removes a whole category of mistake, because there is no path from inside the box to a file anyone else depends on.
Isometric illustration of a sealed workroom with a small pass-through hatch and a separate key cabinet in the outer corridor
Copy-in, copy-out. The room has everything it needs for one job and no door to anywhere else.

The four ways we've watched it leak

None of these were exploits. Every one was a reasonable-looking change that moved the boundary without anyone noticing it had moved — which is why the review question we ask now is never "is this safe?" but "which of the three planes does this touch?"

  • 1Environment inherited at 11pm. A tool needed an API key, and the fastest fix was passing the parent process environment through. The sandbox had been clean for two months and stopped being clean in one line. We now spawn with an explicitly empty environment; adding a variable means editing a manifest, and the manifest gets reviewed like code, because it is code.
  • 2The package registry on the allowlist. Letting the sandbox install dependencies is letting it make arbitrary outbound requests, run arbitrary install hooks and pull arbitrary bytes — with your blessing, through the one hole you deliberately left open. Dependencies now resolve at image build, outside the boundary, from a lockfile a human approved. Inside, the network has never heard of npm.
  • 3The read-only mount that wasn’t. A repo mounted writable so a formatter could run — which also meant the agent could edit the CI workflow, and that pipeline holds deploy credentials. The escalation path never touched the container: it went through CI, on the next push, with full trust. Anything the sandbox can write has to be treated as something an attacker chose the contents of.
  • 4A kill switch that only killed the process.We had a clean stop button and it stopped the container. It did nothing about a token copied out four seconds earlier that stayed valid for another fourteen minutes. Revocation has to live at the issuer, and “stop the job” has to mean “stop the job and burn its credentials.”

A sandbox you can only stop from the inside isn't a sandbox. It's a promise.

Close-up editorial photograph of a red industrial cut-off lever on a control panel, shallow depth of field
The stop button that counts is the one at the issuer, not the one on the runtime.

What we ship on day one

If something on your roadmap is going to run code it wrote itself — a generated report, a file transform, a query nobody reviewed — this is the minimum we put in before the first real task runs. It is about two days of work, and it is dramatically cheaper than retrofitting once the capability set has spread across four tools and three teams.

  • 1An empty environment, asserted in a test. One test that starts the sandbox and fails if any variable matching your secret naming convention exists inside it. This is the highest-value hour on the list, and it is the one that keeps working after everyone forgets the reasoning.
  • 2A broker with a fifteen-minute TTL. Even a crude one. Short-lived and slightly too broad beats perfectly scoped and permanent every time, because expiry is the only control here that enforces itself.
  • 3Default-deny egress with a logged allowlist. You want the log more than the block. A week of denials tells you what your agent actually talks to, and it is never the list you would have written from memory.
  • 4Revocation wired into the stop path.Whatever stops a job must invalidate its tokens in the same call. Test it by stopping a job and then replaying its token — if that request still succeeds, you don’t have a stop button, you have a status change.

Then run the drill, before you think you need it. Take an afternoon, assume the agent is hostile, and give it what an attacker would: drop a file into the input set whose contents are instructions rather than data, point the pipeline at it, and follow where it gets to. Not a design review — an actual run, in staging, against the real manifest. We've done this on four projects and it has found something every time. Twice it was a host on the allowlist nobody could explain. Once it was a token that outlived the job which requested it by six hours.

The uncomfortable part of this architecture is that it makes agents feel less capable, and that is the correct feeling. Every credential you take out is a task the agent can no longer do unattended — which forces the question teams keep deferring: which of these tasks were we ever willing to run without a human, on input we don't control, at three in the morning? Answer that honestly and most of the isolation design writes itself.

Keep Reading

More from the blog

The Engineering Partner You Can Build On

Reliable software takes an experienced team that owns delivery end to end. Here’s the track record behind ours.

11+

Years Building Custom Software

320+

Projects Delivered Across Web, Mobile & AI

85%

Repeat Client Rate

12+

Countries Served Worldwide

Trusted by startups and enterprises worldwide

Work With Us

Let’s create
with purpose

Share your goals, timeline, and challenges — we’ll respond with clarity and next steps.

Ambitious ideas deserve thoughtful execution. Start the conversation and let’s define what success looks like.

Team

Acetrum

Est. 2015

4.9/5

Trusted by
top brands

Services interested in:

By submitting, I confirm I’ve read and agree with Privacy and Cookie Policies.

Newsletter

Signals worth
paying attention

No recycled headlines — just the patterns we’re seeing across real client work, distilled into one read a month.

A curated digest of practical thinking and real-world brand perspectives monthly.

No spam. Unsubscribe anytime.