[C] Contact

Sandboxing Agentic Engineering

What sandboxing is, why AI agents need it, and how the setups used for daily development compare.

On this page (26)

An AI agent runs commands, edits files, calls tools and reads whatever it is pointed at, often for minutes with nobody watching. A sandbox sets in advance the worst thing it can touch when it goes wrong.

Evidence labels:

  • Tested: reproduced in a local test.
  • Docs: taken from the project’s documentation or source.
  • Reported: taken from a third-party write-up or search summary, not checked at the source.

What is sandboxing?

A sandbox restricts what a program can see and do. Something the program cannot switch off enforces it: the kernel, a hypervisor or another machine. Asking an agent to behave is a prompt, not a sandbox.

A sandbox is a policy plus a mechanism. The policy covers five things:

Restriction The question it answers Examples
Filesystem What can it read and write? Only the project folder, with git hooks read-only
Kernel and privileges Which system calls and capabilities can it use? Seccomp filters, dropped capabilities, no root
Network Where can it connect? No network, or an allowlist of domains
Identity What can it authenticate as? No SSH agent, scoped tokens, credentials held by a proxy
Resources and lifetime How much, and for how long? CPU and memory limits, a VM deleted afterwards

The mechanism sets the strength. A permission prompt is enforced by a person clicking “allow”, an OS sandbox by the kernel, a VM by a hypervisor, a separate machine by distance.

Why agentic work needs it

A chatbot answers. An agent acts. Four properties make that a security problem:

  1. Real tools at machine speed. A shell, a git remote, a database connection. A mistake happens before anyone can look.
  2. Everything it reads can be an instruction. Models do not reliably separate data from instructions, so a web page, issue, README, dependency or tool result can steer the agent. This is prompt injection.
  3. Approvals do not scale. People habituate and click “allow”. Anthropic reports that sandboxing cut permission prompts by 84% in internal testing. A sandbox is what makes autonomy affordable.
  4. Behaviour is not deterministic. Design for the worst case, not the expected one.

What can go wrong

Three threats need different amounts of isolation:

  1. Honest mistakes. rm -rf in the wrong directory, a force push, a migration against the wrong database. Almost any boundary handles these.
  2. Prompt injection. The agent reads content that contains instructions and follows them. This is the realistic attack.
  3. A hostile or badly misbehaving model. Less likely. It sets the upper bound on boundary strength.

Simon Willison calls the dangerous combination the lethal trifecta: access to private data, exposure to untrusted content, and a way to communicate externally. With all three, whoever controls one piece of content the agent reads can steer it into sending data out. A sandbox cannot remove the need to read content. It limits what the agent can reach (filesystem, identity) and where it can send (network).

Things to be scared of (& how to turn it into a metric)

This section covers five popular ways agentic work becomes insecure. None needs a kernel exploit, because each uses permissions the agent already has. A prompt injection or an honest mistake can set off any of them.

It ends with a scoring system, 0 to 5 per way and 25 in total. The next section uses it to compare the popular ways of running a coding agent.

Credential theft

Needs no exploit and leaves no trace.

The agent can read anything its user can: SSH keys, cloud CLI tokens (~/.aws, ~/.config/gcloud, ~/.azure), API keys in environment variables and .env files, git credential helpers, tokens in shell history. Taking them is a file read. The repository does not change, so a diff shows nothing.

Forwarding host identity into a sandbox is a quieter variant. An SSH agent socket keeps keys on the host, but anything inside the sandbox can ask the agent to sign with every key it lists (reported, Hannecke). The theft is use, not copying, and lasts as long as the socket does.

SandboxWhat it can reachOutsideAgentinjected promptCredentials~/.ssh/id_ed25519~/.aws/credentials.env · SSH agent socketOutbound trafficany hostgit diffshows nothingAttackeridlereceives keysread keyssendkeys outOpen: keys reachable, egress open
Credential theft is a file read followed by an outbound request. It needs no exploit, and the diff shows nothing.

What reduces it:

  • Do not mount or forward credentials into the sandbox.
  • Use short-lived, narrowly scoped tokens, so a leaked one costs little.
  • Deny egress by default, so what is read cannot leave.
  • Keep the real credential outside the sandbox and inject it at a proxy. Docker Sandboxes do this (reported).
  • Protected-path lists only help partly. Claude Code write-protects credential stores such as ~/.ssh and ~/.aws (docs), which stops changes, not reads. Keeping them out of reach is stronger.
SandboxWhat it can reachOutsideAgentinjected promptCredentialsnothing mountedno keys, no socketsProxyallowlist onlyholds the real tokenAllowed APIAttackerread keysrequesttoken addedsend keysblockedHardened: nothing to steal, nowhere to send it
With nothing mounted, the read finds nothing. The real token stays at the proxy, which adds it only to requests for allowlisted hosts.

Toolchain poisoning

Malicious code in scripts, lockfiles and git hooks that outlives the session.

The agent leaves something behind that a trusted component runs later, outside the sandbox: a git hook or core.fsmonitor setting, a package.json install script, a Makefile target, a CI workflow, a lockfile entry pointing at another source, a virtualenv interpreter, an editor task or project setting. Nothing runs until a person or pipeline runs it, so the damage lands later and with different privileges.

This is the pattern behind the reported configuration-based sandbox escapes (CVE-2026-25725, Pillar Security’s research) and the .git swap shown later (tested). Review can miss it: ignored files, untracked files and .git do not appear in a normal diff.

What reduces it:

  • Write-protect hook, configuration and startup paths. Claude Code does. Codex keeps .git, .agents and .codex read-only (reported).
  • Run builds and tests inside the sandbox, not on the host.
  • Review configuration and lockfile changes, not only source.
  • Verify .git before host git runs in a worktree the agent could write to.
  • Run CI from fresh checkouts with no secrets.

Lateral reach

LAN access, and access to host services or local-network services.

A sandbox’s network is often wider than expected. Reachable targets include services on the host (databases, dev servers, local model endpoints, the Docker socket), cloud metadata endpoints, LAN machines (printers, NAS devices, internal dashboards) and anything the host reaches over a VPN. A host-only network such as Apple container’s --internal blocks the internet but not services on the host (reported, Hannecke). Pillar Security reported Docker socket access affecting Codex CLI, Cursor and Gemini CLI (reported). Claude Code’s proxy refuses loopback, link-local and metadata addresses (docs).

What reduces it:

  • Default-deny egress, including private address ranges.
  • Block cloud metadata addresses.
  • Never mount the Docker socket into a sandbox.
  • Bind host services only to what needs them, and require authentication.
  • On a cluster, use network policies.

Environment persistence

Package caches, shell startup files, cache volumes, temp directories and other footholds.

A foothold survives if the sandbox does, or if the agent can write somewhere shared: shell startup files (.bashrc, .zshrc, .profile), package caches and global installs, scheduled jobs, named volumes reused by later sessions, shared temp directories. Persistent sandboxes make this the default. A Docker Sandboxes VM persists per workspace until deleted (reported), and so does Apple’s container machine (docs).

What reduces it:

  • Ephemeral sandboxes: the modified cache dies with the VM (Hannecke).
  • A read-only root filesystem with a tmpfs for scratch space.
  • No shared cache volumes, or read-only ones.
  • Rebuilt images and protected startup files.

Approval fatigue

Approvals that people click through, and channels that skip approval.

A permission prompt is a human control, and humans habituate. If an agent asks ten times a day, the eleventh “allow” is muscle memory, and an injected request can look exactly like a legitimate one. Sandboxing reduces prompts (Anthropic reports 84% fewer in internal testing). But every approval that lifts the boundary turns fatigue into full access: Codex’s retry without the sandbox, Claude Code’s dangerouslyDisableSandbox. Approval-free modes (--yolo, bypassPermissions) remove the gate. ACP adds another variant: the agent can ask the client for file or terminal access, and in a test the client served a terminal command without asking the user (tested).

What reduces it:

  • A boundary that holds without approvals, so the rare prompt gets read.
  • No in-band way to ask for more: turn off Claude Code’s escape hatch where possible, and strip fs and terminal capabilities from an ACP client.
  • A hard boundary, not prompts, for unattended runs.

Seven questions to ask of any setup

  1. What is mounted, and can the agent write there?
  2. Which host sockets cross the line, and what identity travels with them?
  3. Which capabilities and system calls survive the defaults?
  4. Where can outbound traffic go?
  5. Who patches the guest kernel?
  6. What is still there after the sandbox stops?
  7. What will the host do on the agent’s behalf if it asks?

Which questions decide each fear

The hypervisor appears in none of the five fears, as Hannecke notes. Configuration decides each one:

Fear Decided mainly by questions
Credential theft 1 (what is mounted) and 2 (sockets and identity)
Toolchain poisoning 1 (writable mounts), 3 (what can run) and 7 (what the host does for the agent)
Lateral reach 2 (sockets) and 4 (where traffic can go)
Environment persistence 1 (what is mounted) and 6 (what survives)
Approval fatigue 7 (what the host does for the agent)

How setups are scored

Each setup gets 0 to 5 per fear, 25 at most. Higher is safer. Scores of 4 and 2 sit between the anchors. A 0 means the channel is handed to the agent, such as a forwarded SSH agent or a mounted Docker socket.

Fear 5 3 1
Credential theft Credentials held outside the boundary. Deny-by-default egress Some in reach, such as the agent’s own login. Egress restricted by an allowlist Everything the user can read. Open egress
Toolchain poisoning Writes go to a disposable copy. Hooks, config and startup paths unreachable Known hook and config paths protected. Project scripts and lockfiles writable Writes anywhere the user can
Lateral reach Default-deny network, private ranges included. No host services reachable Internet restricted. Host or LAN partly reachable Full host network and LAN
Environment persistence Environment destroyed after each session Persistent, with protected startup files and limited write paths Startup files, caches and temp directories writable on the user’s machine
Approval fatigue The boundary holds with no approvals, and the agent has no in-band way to ask for more Prompts are rare, but one approval lifts the boundary A person’s click is the main control, or approvals are off with no boundary

The scores are a judgment from documented defaults with approvals on, not measurements. Setups that were not tested are scored conservatively.

Eight setups cover how agents are run day to day. The diagrams show where the agent runs, what encloses it, and where model credentials and network traffic sit. Each setup is scored on the five fears above, 25 at most. Setups run from the lowest score to the highest.

Every setup assumes the agent is used through a terminal, an exec into a container, or the tool’s own app. No editor sits between the user and the agent, so the ACP channel described under special considerations is absent from these scores.

  • A dashed outline marks an isolation boundary.
  • A red outline marks a machine with no boundary around the agent.
  • Red arrows mark ways out of a boundary or channels into the host.

Pi, Oh My Pi and OpenCode in a terminal (5/25)

Your Mac · no boundaryVendorTerminalinteractiveAgent processPi · Oh My Pi · OpenCodepermission rules at mostHost resourcesfiles · ssh keys · LANsame as the userModel loginstored locally by the agentModel APIsubscriptionor API keymodel requests
Pi, Oh My Pi and OpenCode in a terminal: an ordinary process with the user's permissions, and permission rules at most.
12345CredentialsToolchainLateralPersistenceApprovalsScore5/ 25Credentials1everything the user can read; open egressToolchain1writes anywhere the user canLateral1full host network and LANPersistence1startup files and caches writableApprovals1app-level rules at most; a click is the gate
Pi, Oh My Pi and OpenCode in a terminal: 5/25. Higher is safer. Scores are a judgment from documented defaults.

Things it gets right

  • Pi. Its docs point to isolation you bring: a Gondolin extension, plain Docker or OpenShell.
  • Oh My Pi. The README says destructive tools pause for approval (the flags were not checked).
  • OpenCode. Per-tool allow, ask or deny rules for bash, edit, webfetch and external directories, with command patterns and per-agent overrides.
  • Adding a boundary. Run the agent under OpenShell (its README tutorial runs OpenCode) or in a container.

Things it gets wrong

  • No boundary. The agent runs on the machine, as the user. The three agents share one pattern: at most an application-level permission layer.
  • Pi. No built-in permission system. It “runs with the permissions of the user and process that launched it”.
  • Oh My Pi. Its “task isolation” copies workspaces for convenience and is not a sandbox.
  • OpenCode. No sandbox setting was found.
  • Model access. The login sits where the same user can read it. Where any of the three stores it was not found.
  • Network. Unrestricted.

Extra notes

  • Oh My Pi is a fork of Pi. Its README lists OpenAI Codex as an OAuth provider, so a ChatGPT subscription can serve as the model.
  • OpenCode defaults differ between sources, so check the version.

Codex or Claude, local runner (13/25)

Your MacOS sandboxVendorCodex or Claudeapp or terminalas your userShell commandswrites: workspace, tempnetwork: off or proxyOutside the sandboxfile tools · MCPhooks (Claude Code)Escape hatchretry unsandboxedapproval or noneModel APIinferenceprompts, tool calls
Codex or Claude, local runner: the engine runs as the user, only shell commands sit inside the sandbox, and an escape hatch leads out of it.
12345CredentialsToolchainLateralPersistenceApprovalsScore13/ 25Credentials2login on disk; home readable by commandsToolchain3hooks and .git protected; scripts are notLateral3shell only; file tools and MCP are outsidePersistence3file tools write anywhere the user canApprovals2one approval runs outside the sandbox
Codex or Claude, local runner: 13/25. Higher is safer. Scores are a judgment from documented defaults.

Things it gets right

  • A real sandbox for what it covers. Shell commands start inside an OS sandbox (Seatbelt on macOS).
  • Network. Codex: off in workspace-write. Claude Code: a proxy whose allowlist starts empty.

Things it gets wrong

  • Covered surface. Shell commands only. In Claude Code, file tools, MCP servers and hooks run outside the sandbox (docs). Reads and writes made by the file tools are limited only by the user’s own permissions and the approval prompt.
  • Way out. Approval is the boundary. Codex can retry a failed command without the sandbox, with approval. Claude Code’s dangerouslyDisableSandbox prompts in default modes. An approved command then runs with the user’s full access, and the prompt shows the command, not what it can reach. --yolo and bypassPermissions remove the sandbox, the approvals or both.
  • Model access. A subscription login stored on the machine. Codex caches it in ~/.codex/auth.json or the OS keyring (reported).

Extra notes

  • The app and the terminal are front ends for one setup: an engine on the same machine, as the same user. The Codex app is reported to share the CLI’s defaults.
  • Claude’s desktop app also has Cowork, reported to run in a Linux VM.
  • Score: credentials 2, toolchain 3, lateral reach 3, persistence 3 and approvals 2. The agent can ask to leave the sandbox and the covered surface is narrow.

NemoClaw (14/25)

Your machineOpenShell sandboxOutsideNemoClawCLI · blueprintOpenClawalways onone UIDPluginsunsigned(reported)Operatorapproves hostsHost keyscredentials.jsonplaintext, 0600Policy proxybaseline + presetsbinary scopedAllowedhosts+ approvalsonly routeblocked: approve?
NemoClaw: OpenShell underneath, plus an always-on agent, plugins, presets and a host key file.
12345CredentialsToolchainLateralPersistenceApprovalsScore14/ 25Credentials3key out; tool creds and key file exposedToolchain2mutable config; plugins and presets installLateral4OpenShell blocks; Personal tier would be 2Persistence2always on, mutable config, approvals persistApprovals3approvals, with presets that widen access
NemoClaw: 14/25. Higher is safer. Scores are a judgment from documented defaults.

Things it gets right

  • Inherited from OpenShell. Landlock, seccomp, a deny-by-default proxy, binary hashing and credential placeholders. The agent never receives the inference provider key.
  • Baseline policy. Operator approval for blocked hosts.

Things it gets wrong

  • Presets widen it. The Personal tier lets any binary reach public and private addresses on ports 80 and 443 with no HTTP inspection. Package presets (npm, pypi, brew) allow installing code that may be malicious. The github, jira, slack and telegram presets give write access to external systems.
  • Credentials. Provider keys live on the host in ~/.nemoclaw/credentials.json, mode 600, in plaintext (reported, GitHub issue). Tool credentials such as GitHub or Slack tokens have no placeholder mechanism (reported analysis).
  • Limits (docs). Policy is not enforced for an agent started outside the managed entrypoint. A same-UID agent can signal peer processes. Agents can change their own config. Raw filesystem writes bypass the scanners, and base64 or hex secrets evade regex scanning.
  • Plugins. openclaw plugins install in the Dockerfile installs without signature verification (reported).
  • Vulnerabilities. The same bulletin reportedly lists a high-severity NemoClaw flaw. It was not read.

Extra notes

  • An open-source reference stack (Apache 2.0) that runs agents in OpenShell sandboxes. OpenClaw is the default agent. It adds onboarding, managed inference and a baseline network policy.
  • Scored against the baseline policy. The Personal tier would drop lateral reach to 2.
  • Alpha.

Microsoft Quicksand (17/25)

Your machine · macOS, Linux or WindowsQEMU VM · own kernel · restrict=onOutsideHost codePython APIexecute()GuestLinux imageown kernelOverlay diskqcow2save · revertShared foldersCIFS or 9ppaths you chooseguestfwdnot restrictedany host targetInternetFULL modeonlyhost filesskips the block
Microsoft Quicksand: a QEMU VM driven by host code, with outbound blocked by default and the forwards and shared folders as the ways through.
12345CredentialsToolchainLateralPersistenceApprovalsScore17/ 25Credentials3no secrets inside; no injection or allowlistToolchain3overlay disk; mounts write to the hostLateral4own kernel; forwards skip the egress blockPersistence3save and revert optional; default unclearApprovals4no prompts; caller code sets the network
Microsoft Quicksand: 17/25. Higher is safer. Scores are a judgment from documented defaults.

Things it gets right

  • Isolation. A VM with its own kernel and a qcow2 overlay disk.
  • Network by default. MOUNTS_ONLY is the default: user-mode networking with restrict=on, which “blocks all outbound connections from the guest to the real network”. NONE has no network device at all.
  • No root and no Docker. It “needs no root privileges or Docker”.
  • Approvals. The library has no prompts and no in-band way to widen access. The caller’s code picks the network mode and the mounts.
  • State. save, checkpoint and revert keep and roll back state.
  • 9p mounts. They have a read-only option.

Things it gets wrong

  • Forwards are not restricted. A guestfwd rule connects the guest to any host or hostname the host can reach, and hostfwd listens on 127.0.0.1 by default. FULL removes the restriction. The docs describe no domain allowlist and no inspection of traffic.
  • Credentials. Not addressed. No injection and no placeholder scheme was found, so a secret the sandboxed code needs sits inside the VM, or reaches it through a forward the operator builds. The guest agent token is passed on the kernel command line.
  • Files. Host directories share through an SMB3 server Quicksand ships (CIFS, the default, mounted as guest with sec=none). A read-only option for CIFS was not found. Writes land on the host.
  • Control channel. The host reaches the guest agent through a forwarded loopback port. The documented command line also opens a QMP socket on loopback. Whether either is authenticated beyond the token was not checked.
  • Attack surface. QEMU is a large user-space device emulator, which is a wider attack surface than a minimal microVM monitor. That is general knowledge and was not checked against this project’s device list. The README states no threat model, and SECURITY.md is the standard reporting policy.
  • Persistence. save= auto-saves on stop. Whether the overlay is deleted on exit by default was not found.

Extra notes

  • An async Python API to launch, control and snapshot QEMU virtual machines, with a focus on sandboxing AI agents. A library from Microsoft’s GitHub organization (MIT), at version 0.13 to 0.14 in October 2026.
  • Runs on x86_64 and ARM64 on macOS, Linux and Windows, using HVF, KVM or WHPX when available. Without them QEMU falls back to software emulation, 10 to 50 times slower.
  • Prebuilt images include quicksand-agent and a desktop image with a browser.

OpenShell (18/25)

Your machineSandbox · own network namespaceOutsideGatewayproviderspolicy · mTLSAgentLandlockseccompWorkdirread-writerest read-onlyOperatorapproves hostsPolicy proxyhost · port · binaryadds credentialsAllowedendpointsonlyonly routecredentialsblocked: approve?
OpenShell: kernel restrictions on the agent, and one network route through a policy proxy that holds the credentials.
12345CredentialsToolchainLateralPersistenceApprovalsScore18/ 25Credentials4placeholders; Landlock; allowed hosts leakToolchain3system paths read-only; workdir writableLateral5namespace; private ranges blockedPersistence3lives until destroyed; approvals persistApprovals3approvals widen policy until recreated
OpenShell: 18/25. Higher is safer. Scores are a judgment from documented defaults.

Things it gets right

  • Filesystem. Landlock, Linux 6.2 or later. Read-only: /usr, /lib, /etc, /var/log. Read-write: the working directory and /tmp. Everything else is inaccessible. Startup fails if the baseline cannot be enforced. Locked at creation.
  • Process. Drops privileges, disables core dumps, and applies two seccomp filters that block mounts, pivot_root, bpf, ptrace, io_uring_setup, setns and module loading.
  • Network. Deny by default. A proxy checks each connection by host, port and calling binary, pins each binary’s SHA256 on first use, and terminates TLS with an ephemeral CA. A veth pair in a network namespace routes all traffic through the proxy, so a process that ignores proxy variables still cannot bypass it.
  • Credentials. Held by providers. The agent gets an opaque placeholder, which the proxy replaces only for authorized hosts, ports and paths.
  • Independent test. A test of v0.1.2 reported that default-deny egress, binary matching and Landlock held, with logging gaps on the VM driver.

Things it gets wrong

  • Weak L7 defaults. Endpoints without protocol: rest allow any method and path. audit mode, the default, logs violations and forwards them.
  • Still open. Data sent to any allowed endpoint. Application output, which is not scrubbed. Approvals, which widen the policy. The shared kernel, unless the sandbox runs on a VM.
  • Vulnerabilities (reported). NVIDIA’s August 2026 bulletin lists two critical sandbox escapes (CVE-2026-65093 and CVE-2026-65083, CVSS 9.9), a path traversal that bypasses L7 policy (CVE-2026-65092), and command injection in the gateway and exec handler. The sources disagree on some scores.

Extra notes

  • NVIDIA’s open-source runtime (Apache 2.0). A gateway creates sandboxes on Docker, Podman or host virtualization, or on Kubernetes. Linux, macOS on Apple silicon, and Windows through WSL 2 (experimental).

Codex or Claude, cloud runner (19/25)

Your MacVendor cloudIsolated VM or containerApp or terminalstart · reviewControl planequeues the taskAgent + checkoutrepo cloned per taskephemeralNetwork policynone · allowlist · fullset per environmentGitHubtoken at proxytask
Codex or Claude, cloud runner: the agent never runs on the laptop. The environment sets what it can reach.
12345CredentialsToolchainLateralPersistenceApprovalsScore19/ 25Credentials3no local keys; env vars readable; wide listToolchain3fresh checkout; poison can ride the PRLateral5no host, LAN or local servicesPersistence4VM reclaimed; environment cache persistsApprovals4host safe; connector calls still prompt
Codex or Claude, cloud runner: 19/25. Higher is safer. Scores are a judgment from documented defaults.

Things it gets right

  • Isolation. An isolated VM or container with a fresh checkout. No local files, SSH keys or LAN.
  • Claude Code on the web (docs). An Anthropic-managed VM per session. GitHub credentials stay on Anthropic’s servers and a proxy attaches them. Network access defaults to a trusted allowlist, with none, custom and full available.
  • Codex cloud (reported). An isolated container. Internet is off by default while the agent runs, with an optional allowlist.

Things it gets wrong

  • Claude Code on the web (docs). Environment variables are readable by the agent. MCP connector traffic goes through Anthropic’s servers. The Anthropic API stays reachable with network access off.
  • Codex cloud (reported). Internet is available during setup.
  • Remaining exposure. Credentials and tools given to the environment, its network policy, and the output that gets reviewed. The isolation technology was not found documented.

Extra notes

  • The app or terminal starts and reviews the task. The agent runs in the vendor’s infrastructure.

CubeSandbox cluster (19/25)

Agent sideCube clusterKVM microVMOutsideAgentE2B SDKCubeAPIE2B APIauth is opt-inCubeMasterschedulerpicks a nodeCubeletper nodeSandboxown guest kernelsnapshot cloneEgress patheBPF + L7 proxydefault allowAllowedhosts
CubeSandbox in a cluster: a stateless control plane places each sandbox on a node as a KVM microVM. eBPF and an L7 proxy govern its network.
12345CredentialsToolchainLateralPersistenceApprovalsScore19/ 25Credentials3keys stay out; internet on by defaultToolchain4fresh template clone; output still reviewedLateral5eBPF denies private ranges; own TAP eachPersistence3pause, resume and snapshots by designApprovals4caller sets policy; API auth is opt-in
CubeSandbox cluster: 19/25. Higher is safer. Scores are a judgment from documented defaults.

Things it gets right

  • Isolation. Each sandbox is a KVM microVM with its own guest kernel. The VMM runs under a minimal seccomp allowlist.
  • Network. CubeVS is an eBPF switch with one TAP device per sandbox and no shared bridge. Private and link-local ranges are always denied, which covers the host’s network and other sandboxes. CubeEgress is a per-host L7 proxy with domain, path and method rules. A request that matches no rule is denied, and traffic on ports without an L7 rule falls back to L3 and L4 policy.
  • Credentials. Injected as headers at CubeEgress, so the sandbox never sees them.
  • Cluster design. A stateless control plane: CubeAPI (Rust) and CubeMaster (the scheduler), with Redis holding metadata and events. Multi-node deployment is supported.
  • Snapshots. CubeCoW snapshots and clones, auto-pause for idle sandboxes, and cross-node pause and resume through S3 (preview).

Things it gets wrong

  • Internet on by default. AllowInternetAccess=false installs a blanket deny.
  • Credential injection. The template must carry the proxy’s CA. Injection over plain HTTP can leak a credential if DNS is poisoned.
  • Snapshots. A compromised sandbox’s state can be preserved.
  • Management plane defaults. Services bind to 0.0.0.0, CubeMaster has no authentication, Cubelet’s gRPC is plaintext, and CubeAPI accepts every request until an auth callback is set. Bind to a private NIC and firewall it.
  • Kubernetes. Deployment is preview, and its docs were not read.

Extra notes

  • An open-source sandbox service from Tencent Cloud (Apache 2.0), compatible with the E2B SDK. The agent loop runs elsewhere and calls the API to create sandboxes that execute its code and tools. The score covers the sandbox, not the harness.
  • Each compute node runs a Cubelet, which clones a template with CubeCoW and boots the VM through CubeShim and CubeHypervisor (RustVMM and KVM). It needs KVM.

Agent Substrate (21/25, projected)

Kubernetes cluster · node pool per trust levelmicroVM · private netnsOutsideOrchestratore.g. KagentJWT gatewayActorfresh per taskCodex · ClaudeVolumeencryptedno reuseEgress proxyhostname allowlistUDP off · DNS internalCredential storeinjected over HTTPSscoped RBACAllowedhostsonlyonly route
Agent Substrate, hardened (projected): a fresh microVM per task on its own node pool, one allowlisted egress proxy that injects the credentials.
12345CredentialsToolchainLateralPersistenceApprovalsScore21/ 25Substrate defaults · 17Credentials4creds injected; DNS and hosts still leakToolchain4fresh actor per task; reviewed outputLateral5per-tenant nodes; private netns; no UDPPersistence4no snapshot reuse; ephemeral actorsApprovals4admin policy; approvals on few tools
Agent Substrate, hardened (projected): 21/25. Higher is safer. Scores are a judgment from documented defaults.

The defaults score 17/25. The runtime setting alone does not change the score, because the metric does not grade a hypervisor against a user-space kernel. The gains come from compensating for the limitations Substrate lists.

Things it gets right

  • Isolation. The WorkerPool runtime is set to microvm (CHV, Kagent PR #2918, merged in September 2026), not the gVisor default. This moves the boundary from a user-space kernel to a hypervisor. Substrate states that “a linux container is not sufficient or supported”. Each actor has a private network namespace and its own storage partition, and is treated as hostile: “there is no meaningful security boundary inside an actor”.
  • Blast radius. One WorkerPool and node pool per tenant or trust level. A compromised guest then reaches only actors of the same trust level.
  • Network. Default deny, with an explicit hostname allowlist in each EgressPolicy. All TCP goes through an egress proxy that authenticates the actor by certificate and does not trust an actor-supplied hostname or SNI. UDP is blocked at the node. DNS goes to an internal resolver with its own allowlist. Actors cannot reach each other by default, and an authenticating proxy covers actor-to-actor calls.
  • Credentials. The actor never holds a secret. It sends a placeholder header, and the egress gateway swaps in a credential from a provider (Kubernetes Secrets by default) under a default-deny namespace policy. Injection is over HTTPS only, and the provider’s RBAC is scoped to the namespaces it needs. Each actor gets a one-hour workload certificate.
  • Persistence. A fresh actor per task, and no resume of a suspect actor’s snapshot. The operator encrypts the snapshot volume.
  • Approvals. requireApproval only on destructive tools, with the boundary independent of it.
  • Output. Treated as untrusted until reviewed.

Things it gets wrong

  • Allowed hosts and DNS. Both still carry data out.
  • Listed limitations. Node blast-radius containment and inter-namespace network policy are future work, UDP is described as blocked in one page and as passthrough in another, DNS bypasses the proxy while filtering is in progress, storage is unencrypted, restore-time re-authorization is future work, and actor-to-actor authorization is left to the operator. The settings above compensate for these.
  • Cluster tools. The tools Kagent ships (Kubernetes, Helm, Argo, Prometheus) act on the cluster by design.
  • Hypervisor bugs. They remain possible.

Extra notes

  • Agents run as actors on Kubernetes worker pods, with suspend, resume and snapshots. A caller such as Kagent starts them through a gRPC API, behind AgentGateway for JWT and per-tool authorization on A2A and MCP. Runtimes: Go or Python ADK, Codex, Claude, or a custom one.
  • Pre-1.0. The settings above are a projection, and the radar’s outline shows the score with defaults.
  • Substrate is the execution layer. Orchestrators such as Kagent run on top of it.

Best we can do (24/25, projected)

The sandboxed-agent setup, with a change for each deduction it takes. Nothing here has been built or tested as a whole. Each part says what is known.

Your MacmicroVM · one per threadOutsideZedACP · stdioACP guardfs · terminal offfail closedAgentno keysno socketsWork copyno host .gitdeleted afterReview gatepulls a patch from the copyyou review, you applyEgress proxyallowlist onlyadds the tokenModel relayholds the loginGatewayscoped JWTper threadModel APICodexonly way out
Best we can do (projected): a guard on the ACP channel, a disposable VM with a work copy, one egress path that holds the credentials, and a review gate for what comes back.
12345CredentialsToolchainLateralPersistenceApprovalsScore24/ 25ACP, sandboxed agent · 13Credentials5no key in VM; proxy-held token; allowlistToolchain5work copy and reviewed patch; flagged pathsLateral4host answers on two ports (unverified)Persistence5VM per thread, deleted afterwardsApprovals5guard strips fs and terminal; fails closed
Best we can do (projected): 24/25. Higher is safer. Scores are a judgment from documented defaults.
  • MicroVM per thread, deleted afterwards. container run --rm, one per thread, no shared cache volumes. Persistence 5.
  • A work copy, not the live worktree. The VM mounts a copy of the project with no host .git. The host pulls a patch from the copy, you review it, and you apply it. This removes the .git swap (tested) and puts hook, config and startup paths out of reach. Hook, CI and config paths in a patch are flagged for explicit review, and so are lockfile and install-script changes. Toolchain poisoning 5.
  • An ACP guard. Needed only when an editor is in the path. A process between Zed and the container that strips fs, terminal, auth and elicitation from initialize. It fails closed: any agent request outside an allowlist (session/update, session/request_permission) is dropped and answered with an error. The agent keeps its own shell inside the VM. The guard has no in-band way to ask for more power. Approval fatigue 5. The guard was written but not run end to end with Zed.
  • One way out, held by the host. An --internal network, which has no route to the internet. Traffic goes to a proxy on the host. The proxy allows the model relay, the gateway and a package mirror, logs every request, and adds the gateway token to allowed requests, so the VM holds no credential. Credential theft 5. This holds only if nothing else on the host forwards traffic, which the next item enforces.
  • A per-thread gateway identity. A short-lived JWT scoped to read tools by default, minted by a host broker and injected by the proxy. Send and write tools sit behind a narrower role.
  • A host that answers on two ports. --internal does not hide the host: the VM can still reach any host service that listens on the container network. So host services bind to loopback, which the VM cannot reach. The proxy and the model relay bind to the container network address only, and the relay authenticates callers. Firewall rules (pf on macOS) on the container interface drop all other traffic to the host. No Docker socket, SSH agent or home-folder mount. Verify from inside the VM: scan the host address and confirm only the proxy and relay ports answer. Lateral reach 5 by design, 4 until that check passes.
  • OpenShell for the network and credential parts. It provides, as one unit, the network namespace that forces traffic through a deny-by-default policy proxy (which closes the --internal gap), binary-scoped egress rules and credential placeholders. It does not provide the ACP guard or the patch gate, and it shares the host kernel unless it runs on a VM. This combination was not tested.
  • Pinned images. A fixed image digest, rebuilt on a schedule. Builds and tests run inside the VM. CI runs from fresh checkouts with no secrets.

What stays open:

  • Allowed destinations. The model relay, the gateway and the mirror are still channels. Anything the agent can read in the work copy can be sent through them.
  • The patch. Prompt injection can still steer the agent, so the diff can carry poisoned code. The review gate depends on a person reading it.
  • The VM boundary. Hypervisor and tooling bugs are real. Docker Sandboxes had escapes in virtio-fs and a socket relay (reported), and SharedRoot was a mount-level failure.
  • Untested parts. The guard with Zed, the pf rule, the proxy’s token injection and the patch gate.

Ranking

Columns, in order: credential theft, toolchain poisoning, lateral reach, environment persistence, approval fatigue.

Setup Cred Tool Lat Pers Appr Total
Pi, Oh My Pi, OpenCode (terminal) 1 1 1 1 1 5
Codex or Claude, local 2 3 3 3 2 13
NemoClaw 3 2 4 2 3 14
Microsoft Quicksand 3 3 4 3 4 17
OpenShell 4 3 5 3 3 18
Codex or Claude, cloud 3 3 5 4 4 19
CubeSandbox cluster 3 4 5 3 4 19
Agent Substrate, hardened (projected) 4 4 5 4 4 21
Best we can do (projected) 5 5 4 5 5 24

--yolo and bypass modes move the local setup toward the unsandboxed rows. Editor use through ACP adds a channel into the host that these scores exclude. It is scored separately under special considerations.

Special considerations

Some setups add a threat that the scores above leave out.

ACP

The Agent Client Protocol (ACP) connects an editor (the client) to an agent. The client starts the agent as a subprocess and speaks JSON-RPC over stdio. Zed is the example client here. Other editors implement the same protocol. Three facts hold in every variant:

  • Capabilities. The client advertises what it will do for the agent. Zed advertises fs, terminal, auth and elicitation (tested). An agent can use them to ask the client to read files, write files and run commands.
  • Where requests run. The client serves them in its own context, on the host. A test with an agent in a VM showed a terminal command running on the host (tested, indirect evidence).
  • Approvals. The agent decides whether to send session/request_permission. Zed’s tool_permissions rules appear to apply only to its own agent (reported).

The variants differ in what encloses the agent.

Without a sandboxing client (5/25)

Your Mac · no boundaryVendorZedACP clientAgent processOh My Pi · codex-acpas your userHost resourcesfiles · ssh keys · LANsame as the userModel APIinferencemodel requestsfs · terminal
ACP without a sandboxing client: the agent is an ordinary process with the user's permissions, and ACP is a second way to reach the host.
12345CredentialsToolchainLateralPersistenceApprovalsScore5/ 25Credentials1no boundary; open egressToolchain1writes anywhere the user canLateral1full host network and LANPersistence1startup files writableApprovals1the agent decides whether to ask
ACP, no sandboxing client: 5/25. Higher is safer. Scores are a judgment from documented defaults.

Things it gets right

  • Codex adapter. Whether Codex’s own sandbox applies under the codex-acp adapter was not tested, so it may still help.

Things it gets wrong

  • No boundary from the client. Oh My Pi has none.
  • Model access. An OAuth login stored on the host by the agent. Codex caches it in ~/.codex/auth.json (reported). Where Oh My Pi stores it was not found.
  • Network. Unrestricted.
  • Second channel. The agent can ask the client to read, write and run things. Whether codex-acp does so was not tested.

Extra notes

  • Agents: Oh My Pi, or Codex through the codex-acp adapter, which runs as a local subprocess. A ChatGPT subscription is one of the adapter’s authentication methods.

With a sandboxing client (12/25)

Your MacOS sandboxVendorZedACP · stdioAgentwrapped by Zedas your userWritesallowlistedpaths onlyProxydomainallowlistModel APIinferencemodel requestsfs · terminal
ACP with a sandboxing client: the agent process is sandboxed. Requests it sends over ACP are served by the client, outside the sandbox.
12345CredentialsToolchainLateralPersistenceApprovalsScore12/ 25Credentials2reads allowed; fs requests run on the hostToolchain2terminal requests run on the hostLateral3proxy only, but host-served calls are openPersistence3writes limited to allowlisted pathsApprovals2ACP reaches the host without a prompt
ACP, sandboxing client: 12/25. Higher is safer. Scores are a judgment from documented defaults.

Things it gets right

  • OS sandbox. The client launches the agent under Seatbelt on macOS or bubblewrap on Linux.
  • Filesystem. Writes are denied unless a path is allowlisted.
  • Network. Through a host proxy with a domain allowlist. An empty list means no network.

Things it gets wrong

  • Reads. Allowed unless a path is denied (docs).
  • Proxy. It does not inspect traffic, and domain fronting may bypass it (docs).
  • Model access. The agent needs an allowlisted model endpoint and a login it can read from inside the sandbox.
  • Channel gap. fs and terminal requests are served by the client, outside the sandbox. This follows from a test with an agent in a VM. It was not tested with a wrapper.
  • Kernel. Shared with the host.

Extra notes

  • Zed has no setting for this (not found). The agent_servers command can be a wrapper instead, such as srt from sandbox-runtime, which wraps any command.
  • Not tested with Zed.

With a sandboxed agent (13/25)

Your MacApple container VMOutsideZedACP · stdioOMP agentapprovals offno API key/workgit worktreeread-writeModel relayauth + modelCodex loginModel APICodexGatewayMCP serverssubscription callsJWT · MCP callshost terminal
ACP with a sandboxed agent: the VM has its own kernel and one mount. The model relay, the gateway and the ACP channel are the ways in and out.
12345CredentialsToolchainLateralPersistenceApprovalsScore13/ 25best we can do · 24Credentials2no key in the VM; egress open; host terminalToolchain2.git swap worked; host terminal reachableLateral2no egress policy; host services reachablePersistence4container per thread; worktree persistsApprovals3hard boundary, but ACP skipped approval
ACP, sandboxed agent: 13/25. Higher is safer. Scores are a judgment from documented defaults.

Things it gets right

  • VM. Oh My Pi runs in an Apple container VM with its own kernel. The only mount is the git worktree.
  • Model access. The container holds no API key. A relay on the host (the Oh My Pi auth provider and model server) holds the Codex subscription login and serves model requests.
  • Tools. An authenticated gateway, with the MCP servers federated behind it.

Things it gets wrong

  • Channels. A test showed the agent asking Zed to run a terminal command, which ran on the host.
  • Network. container has no egress allowlist. --internal removes the route to the internet, not to the host (reported). Restricting the rest needs a host proxy and host firewall rules.

Extra notes

  • Zed speaks ACP to the agent over stdio.

The three variants are scored with the ACP channel included, on the same five fears. Through a terminal or an exec into the same container, the channel does not exist, and the sandboxed agent would not lose points for it. The ACP guard in the best-we-can-do setup applies only when an editor is in the path.

Variant Cred Tool Lat Pers Appr Total
ACP, no sandboxing client 1 1 1 1 1 5
ACP, sandboxing client 2 2 3 3 2 12
ACP, sandboxed agent 2 2 2 4 3 13

Conclusion

A setup’s name says little about its safety. What counts is what encloses the agent, which channels cross that boundary, and what the agent holds inside it.

  • Nothing scores 25. The lowest setups run the agent as the user with no boundary (5/25). The built-in sandboxes of Codex and Claude Code cover shell commands only, and one approval lifts them (13/25). Isolated clusters and VMs with injected credentials reach 19 to 21, and the best projected setup reaches 24.
  • Credentials and egress decide the most. A VM that holds a key, or can reach the internet freely, leaks everything inside it. The setups at the top keep keys out of the sandbox and route all traffic through one proxy that injects them.
  • Approvals are not a boundary. A setup that depends on a person reading prompts loses points on approval fatigue and lateral reach. A boundary that holds with no approvals, and gives the agent no in-band way to ask for more, scores higher.
  • Channels into the host matter as much as the sandbox. ACP’s fs and terminal requests, a mounted .git, a forward or a shared folder each bypass an otherwise good boundary.
  • Review what comes back. Poisoned code can pass through any sandbox in a patch, so output stays untrusted until a person has read it.

How to choose:

Situation Approach that fits
Quick interactive work on trusted code Codex or Claude Code’s built-in sandbox, with network off or allowlisted
Unattended approval-free mode on a developer machine A VM per container, a narrow mount, an egress proxy, no credentials inside, and no channel for the agent to ask the host
Opening an untrusted repository or dependency A disposable VM holding only a copy of the code, no credentials, and deny-by-default egress
Many agents on a team A cluster setup such as Agent Substrate with hardened settings, behind a gateway

The scores are judgments from documented defaults, not measurements. Projected setups were not built or tested as a whole, and several products were assessed from their documentation alone. Treat a score as a way to compare designs, and check each claim before relying on it.