Back to all posts
Published on · by Renaud Deraison

The agent never left the sandbox

On July 20, 2026, Pillar Security published seven sandbox escapes across Cursor, OpenAI's Codex CLI, Google's Gemini CLI, and Antigravity. Not one of them broke the sandbox. The agent stayed inside, followed every rule, and wrote an ordinary file — a hook config, a virtualenv, a git setting — that a trusted tool on the host read and ran on its own. The sandbox held; the escape happened anyway. Bromure Agentic Coding draws the line where that move has nowhere to land.

Every earlier escape story was about the wall failing. This one is about the wall holding, and the escape happening anyway. The agent obeyed the sandbox, wrote a file it was allowed to write, and a trusted program on the other side of the wall picked that file up and ran it.

A coding agent runs in a sandbox so that when it does something reckless — and it will, because it reads untrusted text all day and believes most of it — the damage stops at the sandbox wall. That is the promise. On July 20, 2026, Pillar Security published seven ways the promise breaks, across four of the most-used agents: Cursor, OpenAI's Codex CLI, Google's Gemini CLI, and Antigravity. BleepingComputer covered it the same week.

Seven is not the surprising number. What the seven share is: in the researchers' own words, "in almost every case, the agent did not need to break the sandbox directly. It only had to write something that a trusted component outside the sandbox would later run, load, scan, or treat as safe."

The move: stay inside, write a file, let the host run it

Think about what a coding agent's sandbox actually contains. It contains the agent process — the thing running the model's decisions. It does not contain the agent's files, because the whole job is to write files: source, configs, build scripts. Those files land on the same disk your other tools read. And your other tools are not sandboxed. Your editor's Python extension is not sandboxed. Your git is not sandboxed. The Docker daemon is not sandboxed. They trust what is on disk, because until recently the only thing writing to that disk was you.

So the agent never touches the wall. It writes a file in exactly the place it is supposed to, and waits for something on the far side to read it. Pillar's seven escapes are seven versions of that one move:

A hook config that runs

In Cursor, the agent writes a workspace .claude hook configuration. Hooks are meant to run commands on editor events — so the command in that file runs, unsandboxed. Assigned CVE-2026-48124, fixed in Cursor 3.0.0.

A Python interpreter, swapped

The agent edits the interpreter inside a project's virtualenv. The editor's Python extension — outside the sandbox — later invokes it, and the swapped binary runs. Tracked as GHSA-p9g2-cr55-cw9c.

A git command trusted by name

Codex CLI's "safe command" allowlist waved through a git invocation because the name looked benign, without reading the arguments that made it dangerous. Fixed in Codex CLI 0.95.0.

A daemon that is a second machine

On several agents the Docker socket was reachable from inside the sandbox. A privileged local daemon is a whole second place to run code, sitting just outside the boundary. Tracked as GHSA-v4xv-rqh3-w9mc.

Antigravity added two more of the same shape — a macOS Seatbelt denylist that missed a case, and a VS Code task configuration the agent wrote that the IDE later executed on its own. Both were rated harder to pull off, but they rhyme with the rest.

The sandbox — heldAgent processobeys every rule,never touches the wallIt is only allowedto write a file…Shared diskhook config ·virtualenv · gitsetting · task fileordinary, allowedThe host — not sandboxedTrusted tool reads the file:Python extension · git ·Docker daemon · task runner…and runs it, outside the box.Code executes as you.Seven escapes, four agents — the sandbox is never breached; the disk it shares is.
The escape that is not an escape. The agent stays inside the sandbox and follows every rule (left). It writes an ordinary, allowed file — a hook config, a virtualenv interpreter, a git setting, a task definition — to the shared disk. A trusted tool on the host that is not sandboxed — the editor's extension, git, the Docker daemon, the IDE task runner — reads that file as part of its normal job and runs what it names (right). The command executes outside the sandbox without the sandbox ever being touched.

Why patching each one does not close the shape

Every one of these got a fix, and they are good fixes. Cursor shipped 3.0.0, Codex CLI shipped 0.95.0, the Docker socket got locked down. If you run these tools, update them. But look at what a fix here has to do. It has to find every file the agent can write that some other program treats as instructions — hook configs, interpreter paths, git metadata, task definitions, lint rules, whatever ships next quarter — and special- case each one. That is a denylist, and Pillar names denylists as the first of four recurring failure modes because "a sandbox profile that starts from 'allow by default' has to remember every dangerous operation the OS exposes." The OS keeps adding operations. The list is never done.

The deeper reason is a sentence in the report that reads like a definition: "If an agent gets to write the future inputs of systems, it was never sandboxed in the first place." A boundary drawn around the agent process, on a machine where the agent shares a disk and a set of trusted daemons with everything else, is drawn around the wrong thing. The blast radius, they write, "is not the agent process; it includes everything the agent can write that the host later trusts." On a developer's laptop, that is nearly everything.

Where Bromure draws the line

Bromure Agentic Coding does not try to enumerate the dangerous files, or teach the sandbox about hooks and virtualenvs and task runners. It moves the boundary. Each profile's agent runs inside a disposable Linux VM on Apple Silicon, one hypervisor away from macOS. In that model the "trusted tool outside the sandbox" — your editor's Python extension, your git, the Docker daemon, the IDE task runner — is not on the other side of a permission wall. It is on the other side of a hypervisor, and it does not read the VM's disk at all.

That is the whole difference. Pillar's move needs two things in the same place: a disk the agent can write, and a trusted program that reads that disk. Put the agent's disk inside the VM and the second thing is gone. The agent can write a hook config, swap a virtualenv interpreter, plant a task definition — every file from all seven escapes — and there is no unsandboxed host tool watching that filesystem to pick it up. Whatever runs, runs inside the box, as the throwaway ubuntu user in a machine that holds nothing.

Process sandbox — one machineAgent (sandboxed)writes an allowedconfig fileHost tools (notsandboxed)read it, run itShared disk — both sides read itCommand runs as you —real keys, source, cloud in reachThe boundary wrapped the process.The disk was shared with the host.Bromure Agentic Coding — hypervisor VMDisposable VMAgentwrites the sameconfig fileDisk livesinside the boxno host toolreads itRuns as ubuntuagainst brm_… decoysEgress gatedat the host proxyNo host tool watches the box's disk.Close the session and it resets.
The same seven files, two boundaries. On a normal setup (left) the agent's sandbox wraps only the process; the file it writes lands on a disk the host's unsandboxed tools read, and the command runs as you, next to your keys and source. Under Bromure Agentic Coding (right) the boundary is a hypervisor around the whole VM: the agent's disk is inside the box, no host tool reads it, and anything that does run runs as a throwaway user against decoy credentials, with every outbound request gated at the host proxy. Close the session and the box resets.

There is a second half to the escapes worth naming, because Bromure answers it too. Suppose a file the agent wrote does get executed by a tool inside the VM — the point of running code is usually to steal something or reach somewhere. Both are dead ends here. The code goes for the credentials that make the trip pay, the Anthropic key, the AWS keys, the GitHub token, and finds decoys: a credential broker on the host injects placeholders like brm_…, a synthetic kubeconfig, and a throwaway SSH key, and swaps the real value in only at the network boundary, on requests to destinations you already approved. And the outbound step — exfiltrating the loot, or reaching a second host — crosses the host proxy, where the true destination is gated on the way out and a destructive action against the cloud and git APIs the profile fronts, a delete or a drop or a terminate, meets a guardrail that can refuse it no matter what the agent was talked into.

Ahead of all of that sits the layer that fits these escapes at their root. Every one starts with an injection — a malicious instruction in a file or a tool result the agent reads, telling it to write the poisoned config in the first place. Bromure scores that untrusted content with an on-device injection detector before the model acts on it. It catches most of this, and a novel enough payload can still slip one classifier, which is exactly why it sits in front of the disposable box rather than in place of it.

The boundary was around the wrong thing

The lasting lesson from Pillar's week is not a list of seven bugs to patch. It is that sandboxing the agent process, on a machine where that process shares a disk and a set of trusted tools with everything you own, draws the line around the wrong thing. The agent does not have to break out if it can write the inputs to something that is already out.

Patching the known files is right, and you should. But it is a race against every future format a host tool decides to trust, and that race does not end. Bromure Agentic Coding steps out of it. It assumes the agent will be talked into writing the poisoned file, and makes sure that when some tool reads it, the tool is inside a throwaway box with decoys for secrets and a gate on the wire — not your laptop, holding your keys. That is the difference between a wall you have to keep patching and a line drawn one level down, where the writing has no reader. Install it and give your agent a machine that is not yours to lose.