Trust inputs
Every control below is designed against prompt injection, not against a malicious
developer.
The layers
.env contents, and any credential your handlers use. The purpose of
the bubblewrap layer is to keep a prompt-injected shell command away from all of
them.
Inside the sandbox:
- The root filesystem is read-only. The user’s workspace is the only writable
path, bound at
/workspace. /appand/tmpare ephemeral tmpfs, which masks the provider dotenv file baked into the image..db/is masked, so the shell cannot read the chat store. Thereadandedittools reject those paths as well.- The environment is cleared and repopulated with
PATH,HOME,TERMandLANGonly. - A user namespace is unshared, which is what blocks reading another process’s
/proc/<pid>/environ, memory or root. - The cloud metadata address range is blocked by an
LD_PRELOADshim that interceptsconnect()for169.254.0.0/16and IPv6 link-local ranges.
Verified behavior
These are the checks the project runs against a live sandbox.Network
curl, pip and git. A
prompt-injected command can then send anything it can read to an arbitrary host.
Turn it off when the agent does not need it. With network=False the sandbox
gets a fresh network namespace and no egress at all. Web search still works,
because it runs outside the sandbox.
What the metadata block does not cover
TheLD_PRELOAD shim stops every program that uses the C library, which covers
what a model writes in practice. It does not stop:
- statically linked binaries, since they never load the shim
- direct syscall invocation, for example through
ctypes - inline assembly
- a child process launched after
unset LD_PRELOAD
Deployment isolation
Deployments under one account share a trust domain: code in one can reach another’s workspace storage. For hard isolation between production and experiments, or between clients, deploy from a separate organization. Each organization is its own tenant with its own boundary.Local development caveat
The sandbox binds the host root read-only. In production that is the runtime container’s filesystem, which holds no host secrets. When you run an agent directly on your machine without Docker, local files such as personal credential stores become readable from the sandbox. Usecycls run, which wraps the agent in Docker, when exercising an agent that
accepts untrusted input with network-enabled bash. Or keep network=False, which
removes the exfiltration path.
Approvals
Isolation bounds what a command can reach. Approvals decide whether it runs at all. Every tool call is classified before it runs:rm and rmdir are not destructive by default, because the sandbox moves
deletions to a thirty day trash. Commands with nothing behind them, such as
shred, mkfs, dd if=, drop table and git push --force, always ask.
See Connectors and MCP for per-tool policy and
organization level switches.
Recommended settings for untrusted users
- Turn off sandbox network access unless the agent needs it.
- Keep deploy credentials out of the image by splitting
.envand.providers.env. - Put anything that must not be readable by a shell outside the workspace, for example behind a connector or a deployed function.
- Use a separate organization for tenants that must not share a trust domain.
Next
Custom loops
Replace the default loop and keep the building blocks.