DEV Community

Zira
Zira

Posted on AI-assisted

A Coding-Agent Sandbox Is Not a Boundary Until Enforcement Lives Outside It

A recent Codex sandbox report is a useful reminder for anyone building or operating coding agents: “read-only” is a capability setting, not proof that the host is safe. The security boundary has to be enforced somewhere the agent cannot rewrite, impersonate, or influence from inside the sandbox.

This is not a claim that every sandbox is broken. It is a design test: can the policy decision point be reached through the same process, memory, filesystem, or tool broker that the policy is supposed to constrain?

What was reported

On September 20, BleepingComputer reported two Codex sandbox escapes disclosed by Accomplish AI researchers. The researchers said they reported both issues to OpenAI on August 12 and that both were fixed within eight days. That timeline and the technical details are researcher-reported, with the public incident covered independently by BleepingComputer.

The first issue, called Heapjack by the researchers, affected a JavaScript tool installed by Codex Desktop. Their write-up says the trusted and untrusted V8 contexts shared a Node process and heap. A token used to distinguish trusted code from untrusted code was therefore readable by the untrusted side. The proof of concept forged a request to the native parent process and launched an application outside the Codex process tree.

The striking detail is the operating mode: the researchers say the path worked in read-only, without an approval prompt. BleepingComputer described the attack scenario as opening someone else’s repository in Codex and asking a question about the code. That makes repository provenance part of the threat model, not just the commands the agent is asked to run.

The second issue, called Overpatch, involved the CLI patch tool. The researchers say a patch could name a path such as /tmp to widen the tool’s calculated write permission, then use a symlink to reach a shell startup file outside the workspace. Again, the interesting failure is not “a bad path slipped through.” It is that attacker-controlled patch input influenced the mechanism that computed its own authority.

According to the researchers and BleepingComputer, the fixes were Codex Desktop build 26.818.21641 for Heapjack and Codex CLI 0.149.0 for Overpatch. Treat those as minimums from the report, not as a substitute for checking the current release and your organization’s advisories.

The shared design failure

Both paths have the same shape:

  1. The agent supplied input to a tool.
  2. The tool used that input while deciding what the agent was allowed to do.
  3. The enforcement state was reachable from the same trust domain as the untrusted code.
  4. A successful request crossed into a more privileged process or path.

That is why “the model cannot directly call open” or “the shell cannot write $HOME” is not enough. The real questions are:

  • Can an untrusted process inspect the authority token, broker pipe, or shared memory used by the trusted side?
  • Can a path alias, symlink, mount, archive extraction, or parent-directory calculation change the meaning of “inside the workspace”?
  • Can a tool outside the sandbox be induced to perform the action on the agent’s behalf?
  • Does a restart preserve a malicious config, hook, plugin, or shell profile?

OpenAI’s current security guidance describes sandboxing and approvals as separate layers: the sandbox limits what commands can technically do, while approval policy controls when Codex asks before acting. The same documentation warns that settings such as full access deliberately widen the trust boundary. That is good operational guidance, but it does not remove the need to test the implementation boundary itself.

A practical test matrix for agent builders

You do not need an exploit reproduction to catch many classes of boundary mistake. Add adversarial tests around the policy decision point.

1. Test repository provenance

Run an untrusted repository in the strictest mode and ask the agent to inspect it. Verify that it cannot:

  • create or modify files outside the intended root;
  • launch a host application;
  • connect to a Docker, SSH, credential, or other privileged Unix socket;
  • alter global agent configuration; or
  • cause a trusted helper to perform any of those actions.

Record both the agent-visible result and host-side evidence. A clean chat response is not an audit record.

2. Test path semantics, not only path strings

Exercise symlinks, .. traversal, hard links where applicable, bind mounts, archive extraction, temporary directories, case folding, and platform-specific path forms. Test the parent directory and the final target separately. If a tool calculates permission from a path supplied by the agent, make that calculation happen in a process that cannot be modified by the agent.

3. Separate policy from execution

The component deciding “allowed” should not share mutable authority state with the component executing untrusted code. A stronger pattern is an outer VM or OS boundary, a narrow host broker, and credentials that never enter the guest. The broker should validate an explicit capability request against policy; it should not accept a token or path whose meaning the guest can redefine.

4. Test the recovery boundary

After a failed run, rebuild or reset the environment and check global config, shell startup files, plugin registrations, temporary mounts, and cached credentials. A sandbox that blocks the first action but leaves a persistent hook behind has not recovered cleanly.

5. Treat egress as its own control

Filesystem isolation does not stop data exfiltration if the agent can reach the network. Start with no network, then add narrowly scoped destinations through a policy the guest cannot disable. Keep real credentials outside the guest where possible, and assume anything placed inside an untrusted runtime can be read by code running there.

The rule I would use

The agent may be untrusted. The policy engine must be more trusted than the agent.

If both live in one process, share a heap, share a mutable config, or allow attacker-controlled input to define the permission calculation, call it a defense-in-depth control rather than a hard security boundary.

The useful review question is not “does this feature say sandbox?” It is: what independent mechanism still says no when the agent tries to make the sandbox say yes?

Sources and evidence

Top comments (0)