Zerobox: deny-by-default process sandboxing built on the Codex runtime
Lightweight, cross-platform process sandboxing powered by OpenAI Codex's runtime. Sandbox any command with file, network, and credential controls.
At a glance
- What is it?
- Zerobox wraps an arbitrary command in a sandbox that blocks writes, network and environment inheritance unless you explicitly allow them, and it substitutes credentials at a proxy so the child process never holds the real key. It is aimed at people running AI-generated code or LLM tool calls on their own machine, and its main constraint is that it only covers macOS and Linux today.
- Who is it for?
- Adopt Zerobox if you already run untrusted or model-generated commands on a macOS or Linux developer machine and want a single binary that blocks writes and outbound traffic by default, with credential substitution handled at the proxy rather than in the child process. Do not adopt it if you need Windows coverage, if your workload depends on Node.js fetch reaching the network without extra flags, or if you want a container or VM boundary rather than a process-level one.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 121 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem Zerobox targets: commands you did not write
A large share of code executed on developer machines in 2026 was not written by the person running it. Agent frameworks emit shell commands, LLM tool calls run scripts, and a build step may pull a postinstall hook from a registry. The usual answer is a container or a VM, which costs image build time, a runtime to install, and a volume-mount decision for every path the process needs. Zerobox takes the opposite position: run the command directly on the host, but interpose a sandbox that denies writes, network access and environment inheritance unless a flag says otherwise. The README states this as "Deny by default: Writes, network, and environment variables are blocked unless you allow them." That default matters more than the flag list. Most sandboxing tools ask you to enumerate what to block, which means a new attack surface is unprotected until someone updates the policy. Zerobox inverts it, so an unfamiliar command that tries to write to ~/.ssh or open a socket to an unlisted host fails without any policy authoring. The audience is narrow and specific: developers running AI agents, MCP servers and generated scripts on their own workstations, plus teams that want per-tool isolation inside a larger agent process rather than sandboxing the whole thing.
How the sandbox is assembled: Codex runtime, proxy, and a placeholder scheme
Zerobox is written in Rust and describes itself as "powered by OpenAI Codex's runtime", so the isolation primitives are not original to this project. The repository layout points at a vendored or synced copy of that runtime: the from-source install runs ./scripts/sync.sh before cargo build --release -p zerobox, which suggests the Codex sandbox code is pulled in at build time rather than depended on as a published crate. On top of that runtime, Zerobox layers three controls. File access is allow or deny by path. Network is filtered by domain. Environment variables are filtered by name, with only PATH, HOME, USER, SHELL, TERM and LANG inherited by default. The credential mechanism is the part worth reading twice. The child process sees a placeholder of the form ZEROBOX_SECRET_a1b2c3d4e5, and the real value is substituted by a network proxy only for the hosts named in --secret-host. The README's own example shows echo $OPENAI_API_KEY returning the placeholder inside the sandbox, while a curl to api.openai.com carrying that variable in an Authorization header arrives at the server as the real sk-proj key. That is a genuine architectural choice: the secret is not in the process environment, so a prompt injection that convinces an agent to print its env, or a malicious dependency that reads process.env, gets a string that is useless outside the proxy. It also means the proxy sits in the data path for every allowed request, and the README notes the consequence plainly: Node.js fetch does not respect HTTPS_PROXY by default, so Node code inside the sandbox needs --use-env-proxy to route through it.
Getting it running: install channels and the flags that matter
There are five install paths. The shell installer is curl -fsSL https://raw.githubusercontent.com/afshinm/zerobox/main/install.sh | sh, and there are packages on npm (npm install -g zerobox), PyPI (pip install zerobox) and crates.io (cargo install zerobox). Building from source is git clone https://github.com/afshinm/zerobox && cd zerobox && ./scripts/sync.sh && cargo build --release -p zerobox. The invocation shape is zerobox [flags] -- <command>. A bare run gives no writes and no network: zerobox -- node -e "console.log('hello')". From there you open specific doors. --allow-write=. grants writes to the current directory only. --allow-net=api.openai.com grants outbound traffic to one domain, or --allow-net with no value grants it generally. --secret OPENAI_API_KEY=sk-proj-123 paired with --secret-host OPENAI_API_KEY=api.openai.com scopes a credential to one host; omit the host flag and the README warns the secret is passed to all domains. Environment control has four separate flags: --allow-env to inherit everything, --allow-env=PATH,HOME,DATABASE_URL for a named list, --deny-env=AWS_SECRET_ACCESS_KEY to subtract from a broad allow, and --env NODE_ENV=production to set values outright. Finally there is --restore, which records filesystem changes during the run and undoes them afterwards, and --snapshot, which records without undoing so you can inspect later through zerobox snapshot list, zerobox snapshot diff <session-id> and zerobox snapshot restore <session-id>. The snapshot workflow is the one I would reach for on an npm install inside a sandbox, because it gives you a diff of what the package actually touched before you decide whether to keep it.
Where the model breaks down: proxy traffic, Windows, and the sync dependency
The credential design has a failure mode stated in the README itself. Because substitution happens at the proxy, any client that ignores proxy environment variables will either fail to reach the network or, worse, reach it without the substitution, depending on how the allow-list is configured. Node.js fetch is the named case and --use-env-proxy is the named fix, but the general lesson is that every runtime you launch inside the sandbox must be checked against the proxy. A statically linked binary with its own TLS stack is the kind of thing that will not cooperate. The second limitation is platform coverage. The README says macOS and Linux, with Windows listed as planned, so anyone on Windows is outside the supported set entirely rather than in a degraded mode. Third, the Codex runtime is synced rather than pinned to a published version, and the README does not state which Codex revision a given Zerobox release corresponds to. That is a supply-chain question worth resolving before you put this in front of untrusted code, because the isolation guarantees come from that runtime, not from Zerobox's flag parsing. Fourth, the project is young. The three most recent releases, v0.3.1 through v0.3.3, all landed within roughly three hours of each other on 2026-05-17, which is consistent with rapid patching rather than a settled interface. Treat the CLI surface as moving.
How it differs from containers and from gVisor-style isolation
The obvious alternative is Docker. The difference is not degree of isolation, it is where the boundary sits and what it costs to cross. A container gives you a kernel-level namespace boundary, a filesystem image, and a network namespace you configure with rules; it also gives you an image to build, a daemon to run, and a mount decision for every path the process needs. Zerobox gives you a process-level boundary on the host filesystem, no daemon, no image, and a single binary the README describes as having no Docker and no VMs. The practical consequence is that a Zerobox-sandboxed process sees the real host paths you allowed, so ./dist means the same ./dist your editor sees, with no bind mount to keep in sync. The cost is that you are relying on the Codex runtime's syscall filtering rather than on kernel namespaces, and the README does not document which mechanism is used on each platform. If your threat model includes a determined attacker with a kernel exploit, a VM is the right tool and Zerobox is not. If your threat model is a language model that hallucinated rm -rf or a package that phoned home during install, the process-level boundary is proportionate and much cheaper to invoke, which is the whole argument for using it per tool call rather than per session.
Maintenance, licensing, and what the release cadence implies
Zerobox is Apache-2.0 and the repository is not archived. Apache-2.0 is a permissive licence with an explicit patent grant and a requirement to preserve notices and state changes; it does not impose copyleft on your code. That is a factual description of the licence text, not legal advice, and if you redistribute a modified binary you should read the NOTICE and modification-marking clauses yourself. The maintenance picture is harder to read from the material available. Three patch releases in one evening suggests active work, but it also means the version you pin today may be superseded by a fix tomorrow, and the README does not include a compatibility or deprecation policy for the flag set. The dependency on a synced Codex runtime is the real ongoing cost: when that runtime changes its sandboxing behaviour, Zerobox has to re-sync and re-verify, and nothing in the supplied material says how that is tracked or tested beyond the presence of a CI workflow at .github/workflows/ci.yml. Budget for re-testing your allow-lists after every upgrade rather than assuming flag semantics are stable across minor versions.
SDK surface and the per-tool sandboxing pattern
Zerobox ships SDKs for Rust, TypeScript and Python, with the README claiming a consistent API across the three. The examples directory is where the intended usage pattern is clearest. examples/ai-agent-sandboxed wraps an entire agent process with secrets, so the API key is never visible to the agent at all. examples/ai-agent uses the Vercel AI SDK with per-tool sandboxing, meaning the parent agent runs normally and individual tool calls are isolated. examples/workflow runs Vercel Workflow with sandboxed durable steps. Those three cover genuinely different granularities, and the middle one is the interesting case: if you only sandbox the tools that touch the filesystem or the network, you avoid paying the sandbox cost on pure computation, and you keep the agent's own state management outside the boundary where it can still function. The README does not document the SDK call signatures in the main file, only linking to crates/zerobox/README.md, packages/zerobox/README.md and sdks/python/README.md, so evaluating the programmatic path means reading three separate documents. If you are choosing between the CLI and the SDK, the CLI is better documented in the material available here.
Editorial conclusion
Adopt Zerobox if you already run untrusted or model-generated commands on a macOS or Linux developer machine and want a single binary that blocks writes and outbound traffic by default, with credential substitution handled at the proxy rather than in the child process. Do not adopt it if you need Windows coverage, if your workload depends on Node.js fetch reaching the network without extra flags, or if you want a container or VM boundary rather than a process-level one. Before trusting it, verify four things yourself: that the default deny actually blocks a write outside your allowed path on your kernel, that --secret-host substitution works for the exact hostnames your tools call, that the proxy environment variables are honoured by every runtime you launch inside the box, and which Codex revision the vendored runtime is synced to via ./scripts/sync.sh.
Community notes