Sandboxing agents requires real enforcement

EM
Author
Erik Mejia
Published
Reading time
6 min read
Category
Engineering

How to assess a coding-agent sandbox: file access, network rules, child processes, and the actions that still need approval.

This note draws on OpenAI’s account of building a Windows sandbox for Codex. The review questions below are our interpretation of the engineering lessons. Read the source article.

Coding agents create a security problem with a practical twist. The software needs to use the same messy tools a developer uses: shells, package managers, test runners, version control, language runtimes, and project-specific commands. If the environment blocks too much, every useful task becomes an approval request. If it blocks too little, a mistaken command can operate with the full power of the user account.

The correct question is not whether an agent is trustworthy. It is where the operating system draws the boundary when an agent, a dependency, or a child process behaves unexpectedly.

Coding agent sandbox boundary An original diagram showing an agent command flowing through a restricted runner into a constrained process tree. OS-enforced sandbox boundary Agent request task and approval scope Restricted runner constrained identity Process tree shell, tools, and children workspace writes network policy An original diagram of a coding-agent sandbox boundary.

Safety that tools can bypass is not a boundary

Advisory controls still help

Many restrictions are convenient but advisory. Environment variables can point HTTP clients at a dead proxy. A wrapper can hide a binary from the path. A command policy can deny common operations. These controls are useful as defense in depth, but they rely on the process cooperating.

The boundary must survive non-cooperation

A package can ignore proxy settings. A binary can open a socket directly. A script can find an executable by absolute path. A child process can make choices the parent never anticipated.

That is why a sandbox must be enforced below the application layer. The operating system needs to decide whether a process may read a file, write a directory, create a network connection, or launch a descendant. The process should not be able to opt out of the restriction it is meant to obey.

This principle is simple, but it changes implementation decisions. A policy that looks strict in a configuration file may not be strict where it matters.

Check the whole process tree

Descendants inherit the boundary

An agent rarely runs one command. It launches a shell, which launches a package manager, which may launch a compiler, test worker, Git process, or local server. The sandbox must apply to that whole chain.

That makes a list of approved command names insufficient. The relevant question is whether every descendant inherits a constrained identity and constrained permissions. If the agent can start an unrestricted child, the sandbox has a hole at its most important boundary.

The process tree also explains why least privilege needs a clear model. It is reasonable for an agent to read project files. It may be reasonable to write inside the selected workspace. It is usually not reasonable to write across the user’s home directory, alter credentials, or contact arbitrary services without permission.

Those are different capabilities. A useful sandbox should express them independently.

Filesystem policy should be narrow and inspectable

Scope writes to the work surface

For a coding workflow, the minimum useful write surface is usually smaller than a user account. A workspace might be writable, while its version-control metadata, tool configuration, or sibling directories remain protected. Temporary paths may be writable for builds without becoming a path to the rest of the machine.

The hard part is not naming one directory. It is making the policy hold when tools resolve symlinks, follow relative paths, create files in caches, or spawn helpers that inherit the agent’s permissions. A robust boundary uses the platform’s own access-control mechanisms and validates the exact targets it grants.

It is also important to distinguish the sandbox from the repository policy. A sandbox might allow a change to a source file but preserve the right to require approval before a branch, commit, deployment, or external message. Technical permission and human authorization are separate controls.

Network access needs an explicit default

Allow exceptions deliberately

Network access is easy to overlook because normal development depends on it. Dependency installation, API calls, source control, telemetry, and documentation all use the network. But a coding agent with unrestricted outbound access can send source code or credentials to destinations the user did not intend.

That does not imply the answer is “never allow network access.” It means the default should be understandable and the exception should be deliberate. A team can allow a task to access a specific package registry, local service, or approved API. It should not quietly turn broad network reach into the default because a build happens to need it.

An enforced network policy must follow the agent’s process tree. Blocking one launcher binary is not enough if the same task can spawn another process that reaches the network outside the rule.

Compatibility is a security requirement too

Make the safe path usable

Strong isolation that breaks normal work will push users toward unsafe modes. If the safe path requires approving every file read or command, people will choose broad access because it is the only way to finish the job.

That is why agent security is not solved by maximizing restrictions. The system needs to protect meaningful boundaries while retaining the operations that make the tool valuable. Reading project context, running tests, and editing approved files should be low friction. Expanding the write surface, reaching the network, or taking irreversible action should be visible and intentional.

A useful default lets normal development work proceed within clear limits.

A small threat model for daily work

Ask four scope questions

When configuring an agent environment, I find it useful to ask four questions:

  1. What should this task be able to read?
  2. What should it be able to write without a separate decision?
  3. Which destinations, if any, should its processes be able to reach?
  4. Which actions still require a human approval even if the sandbox permits them?

The answers are context dependent. A local documentation update has a different risk profile from a migration, a production deployment, or a task that handles customer data. The point is to make those differences explicit before a model generates a command.

What I take from the Windows example

Compose the controls the platform provides

The Windows work is a good reminder that platform primitives often do not map cleanly to an agent’s needs. A conventional application may know every resource it needs in advance. An agent-driven development task is open ended by design.

That does not remove the need for enforcement. It requires a composition of controls: a constrained identity, scoped filesystem permissions, a network boundary, and a command-launch path that preserves those restrictions for descendants.

The implementation may be more complex than a lightweight wrapper. The alternative is complexity hidden in unsafe assumptions.

Test the boundary

Good sandboxing is not a promise that nothing can go wrong. It is a system that limits the blast radius when something does. The user should be able to understand what the agent can do, expand that scope when needed, and rely on the platform to enforce the line.

Check both permitted and blocked actions. Confirm that child processes cannot bypass the same restrictions.

Get new notes

Tell us what needs to work.

Describe the work you want to improve.