alt.hn

3/30/2026 at 2:32:36 PM

Show HN: Zerobox – Sandbox any command with file, network, credential controls

https://github.com/afshinm/zerobox

by afshinmeh

4/1/2026 at 6:15:16 PM

This looks really good - the CLI interface design is solid, and I especially like the secrets / network proxy pattern - but the thing it needs most is copiously detailed documentation about exactly how the sandbox mechanism works - and how it was tested.

There are dozens of projects like this emerging right now. They all share the same challenge: establishing credibility.

I'm loathe to spend time evaluating them unless I've seen robust evidence that the architecture is well thought through and the tool has been extensively tested already.

My ideal sandbox is one that's been used by hundreds of people in a high-stakes environment already. That's a tall order, but if I'm going to spend time evaluating one the next best thing is documentation that teaches me something about sandboxing and demonstrates to me how competent and thorough the process of building this one has been.

UPDATE: On further inspection there's a lot that I like about this one. The CLI design is neat, it builds on a strong underlying library (the OpenAI Codex implementation) and the features it does add - mainly the network proxy being able to modify headers to inject secrets - are genuinely great ideas.

by simonw

4/1/2026 at 6:22:19 PM

> There are dozens of projects like this emerging right now. They all share the same challenge: establishing credibility.

Care to elaborate on the kind of "credibility" to be established here? All these bazillion sandboxing tools use the same underlying frameworks for isolation (e.g., ebpf, landlock, VMs, cgroups, namespaces) that are already credible.

by kjok

4/1/2026 at 6:25:25 PM

The problem is that those underlying frameworks can very easily be misconfigured. I need to know that the higher level sandboxing tools were written by people with a deep understanding of the primitives that they are building on, and a very robust approach to testing that their assumptions hold and they don't have any bugs in their layer that affect the security of the overall system.

Most people are building on top of Apple's sandbox-exec which is itself almost entirely undocumented!

by simonw

4/1/2026 at 6:59:44 PM

> The problem is that those underlying frameworks can very easily be misconfigured.

Agreed. I'm sure a number of these sandboxing solutions are vibe-coded, which makes your concerns regarding misconfigurations even more relevant.

by kjok

4/1/2026 at 11:41:27 PM

I'm sure 100% of them are vibe coded. We were all wondering where this new era of software is, and now it's here, a bunch of nominally different tools that all claim to do the same thing.

I'm thinking the LocalLLM crowd should take their LLMs to trying to demolish these sandboxes.

by cyanydeez

4/1/2026 at 6:16:35 PM

Simon! Thanks. I appreciate your comment and totally agreed. I will improve the docs as well as tests.

by afshinmeh

4/2/2026 at 9:15:28 AM

Oh wow, this looks nicely done! It's also nice that it's cross platform. I've done something similar with https://github.com/Gerharddc/litterbox which takes things a bit further by allowing you to easily sandbox your entire development environment (i.e. IDE and everything) using containers. Unfortunately I have not gotten around to the network sandboxing part though, that seems very tricky to get useful without being too "annoying".

by Gerharddc

4/1/2026 at 8:01:55 PM

Compare with and steal any ideas you like from mine if you like. I've got a semi-decent curl|bash pattern covered, and also add network filtering via pasta (which may be more robust than rolling your own). https://github.com/reubenfirmin/bubblewrap-tui

by smallerfish

4/1/2026 at 8:04:13 PM

Ohh! thanks for sharing this. You are using DNS proxy which is interesting and useful if a process doesn't respect the HTTPS_PROXY/HTTP_PROXY/etc. env vars that I'm injecting. I will take a look, very interesting.

by afshinmeh

4/1/2026 at 6:08:49 PM

You should probably add a huge disclaimer that this is an untested, experimental project.

Related, a direct comparison to other sandboxes and what you offer over those would be nice

by wepple

4/1/2026 at 6:15:39 PM

I agree to some extend. I'm using the OpenAI Codex crates for sandboxing though, which I think it's properly tested? They launched last year and iterated many times. I will add a note though, thanks!

by afshinmeh

4/1/2026 at 5:45:51 PM

Personally I would probably always reach for a docker container if I want a sandboxed command that can run identically anywhere.

I appreciate that alternate sandboxing tools can reduce some of the heavier parts of docker though (i.e. building or downloading the correct image)

How would you compare this tool to say bubblewrap https://github.com/containers/

by eluded7

4/1/2026 at 5:50:50 PM

The text says that it uses OS-level tools, specifically bubble wrap on Linux.

by ebb_earl_co

4/1/2026 at 6:19:31 PM

That's right. It uses the same kernel mechanisms as Docker, the runtime is different though (bwrap on linux, seatbelt on mac, etc.)

by afshinmeh

4/1/2026 at 8:35:25 PM

[flagged]

by hrmtst93837

4/1/2026 at 11:05:48 PM

You are a bot. Botting HN is not allowed. Leave.

by sebmellen

4/2/2026 at 7:11:13 AM

Nope, just a guy who's been lurking since 2011 and finally has opinions. I'll work on being less organized about it.

by hrmtst93837

4/1/2026 at 11:07:01 PM

Hey - I'd love for you to add a documented / standard way to use this inside dockers so we can use build on it for various agentic efforts. I've solved getting bubblewrap to work inside a docker once for the nanobot project, but the folks there are dragging their feet on incorporating sandboxing.

https://github.com/HKUDS/nanobot/pull/1940

by rao-v

4/1/2026 at 11:13:08 PM

I've been testing this on Docker today, including the credential injection, env vars, net calls control. I will add more docs but one interesting use case would be to have something like `zerobox --profile nanoclaw -- nanoclaw`, or something similar.

I'd like to hear your thoughts.

by afshinmeh

4/2/2026 at 12:26:18 AM

I'll give it a shot later today, but basically you need a pretty specific seccomp profile (see my example - I pulled from the podman repo) to allow bubblewrap to run inside an unpriviledged docker.

by rao-v

4/1/2026 at 9:01:10 PM

> zerobox --secret OPENAI_API_KEY=$OPENAI_API_KEY

Linux by default allows all users to read CLI arguments of running processes. While it looks like your bwrap invocation prevents the sandbox from looking at this process (--unshare-pid), any other process running on your system can read the secret.

by lights0123

4/1/2026 at 9:13:23 PM

That's true and the expected behaviour but I see your point. The example there is not great, I should've used `sk_s123...` to show that you are passing the env var to the sandbox as opposed to setting it on the host, then proxying it. I will update it.

by afshinmeh

4/1/2026 at 8:23:35 PM

It’s terrific to see this. I’m definitely going to give it a whirl. I’ve been working on a specific JavaScript isolate[^1]. This is great source of inspiration for it.

[^1]: https://github.com/jonathannen/hermit

by jwilliams

4/1/2026 at 8:39:50 PM

I'd love to hear your thoughts! I've been primarily testing this with Bun + Vercel AI SDK for tool call sandboxing.

by afshinmeh

4/1/2026 at 5:48:20 PM

Very interesting. I just started researching this topic yesterday to build something for adjacent use cases (sandboxing LLM authored programs). My initial prototype is using a wasm based sandbox, but I want something more robust and flexible.

Some of my use cases are very latency sensitive. What sort of overhead are you seeing?

by time0ut

4/1/2026 at 7:54:39 PM

Wasm sandboxes are fast for pure compute but get painful the moment LLM code needs filesystem access or subprocess spawning. And it will, constantly. Containers with seccomp filters give you near-native speed and way broader syscall support — overhead is basically startup time (~2s cold, sub-second warm). For anything IO-heavy it's not even close. We're doing throwaway containers at https://cyqle.in if anyone's curious.

by qalfy

4/1/2026 at 10:45:54 PM

I will run the same benchmark test on wasm sandboxes just to be able to compare it with Zerobox. I will share the results tomorrow.

by afshinmeh

4/1/2026 at 5:58:33 PM

Again, it’s blacklisting so kind of impossible to get right. I’ve looked at this many times, but in order for things to properly work, you have to create a huge, huge, huge, huge sandbox file.

Especially for your application that you any kind of Apple framework.

by jbverschoor

4/1/2026 at 6:18:01 PM

This doesn't look like it's blacklisting to me. It's an allowlist system:

  --allow-net=api.openai.com # Explicitly allow access to that host

  --allow-write=config.txt # Explicitly allow write to that file

by simonw

4/1/2026 at 6:20:43 PM

That's correct. The pattern is: reads allowed, write and network I/O blocked by default.

```

zerobox -- curl https://example.com

Could not resolve host: example.com

```

by afshinmeh

4/1/2026 at 6:24:10 PM

Oh so it allows ALL file reads?

I'd feel safer with default-deny on reads as well, but I know from past experience that this gets tricky fast - tools like Node.js and uv and Python all have a bunch of files they need to be able to read that you might not predict in advance.

Might still be possible to do that in a DX-friendly way though, if you make it easy to manually approve reads the first time and use that to build a profile that can be reused on subsequent command invocations.

by simonw

4/1/2026 at 6:28:05 PM

I agree and you can deny all reads like this:

```

zerobox --deny-read=/ -- cat /etc/passwd

```

That being said, what the default DX shouldl be? What paths to deny by default? That's something I've been thinking about and I'd love to hear your thoughts.

by afshinmeh

4/1/2026 at 6:33:40 PM

That's a really tough question. I always worry about credentials that are tucked away in ~/.folders in my home directory like in ~/.aws - but you HAVE to provide access to some of those like ~/.claude because otherwise Claude Code won't work.

That's why rather than a default set I'm interested in an option where I get to approve things on first run - maybe something like this:

  zerobox --build-profile claude-profile.txt -- claude
The above command would create an empty claude-profile.txt file and then give me a bunch of interactive prompts every time Claude tried to access a file, maybe something like:

  claude wants to read ~/.claude/config.txt
  A) allow that file, D) allow full ~/.claude directory, X) exit
You would then clatter through a bunch of those the first time you run Claude and your decisions would be written to claude-profile.txt - then once that file exists you can start Claude in the future like this:

  zerobox --profile claude-profile.txt -- claude
(This is literally the first design I came up with after 30s of thought, I'm certain you could do much better.)

by simonw

4/1/2026 at 6:38:42 PM

Fantastic! I like that idea. I'm also exploring an option to define profiles, but also have predefines profiles that ships with the binary (e.g. Claude, then block all `.env` reads, etc.)

by afshinmeh

4/1/2026 at 7:06:43 PM

Being able to mix and match profiles would be neat.

by simonw

4/1/2026 at 7:11:12 PM

Give me 2 days :)

by afshinmeh

4/2/2026 at 2:34:19 AM

The `--build-profile` / `--profile` thing is a good idea, but typically you'd want to just save all of the access that the program does without prompting.

Programs will access many files and directories on startup, and it would be extremely tedious to have to manually approve each one. So you'd auto-approve all and save them to the profile. This is TOFU principles applied to sandboxing. The assumption being that "this first time I run it naked, it's unlikely to do anything malicious, let me enforce that behavior for the future."

by gslepak

4/1/2026 at 6:18:41 PM

That's interesting, thanks for sharing that. Could you elaborate a bit more? I'd like to understand the use case is a bit better.

by afshinmeh

4/1/2026 at 6:17:02 PM

Technical debt is not always bad. Deliberate technical debt taken on with eyes open to ship faster is a legitimate business strategy. The problem is accidental technical debt from poor decisions compounding silently.

by zephyrwhimsy

4/1/2026 at 6:34:08 PM

I trust sandbox-exec more, or Docker on Linux. Those come from the OS, well tested and known.

MITM proxy is nice idea to avoid leaking secrets. Isn’t it very brittle though? Anthropic changes some URL-s and it’ll break.

by mdavid626

4/1/2026 at 6:36:14 PM

Thanks for sharing that. Zerobox _does_ use the native OS sandboxing mechanisms (e.g. seatbelt) under the hood. I'm not trying to reinvent the wheel when it comes to sandboxing.

Re the URLs, I agree, that's why I added wildcard support, e.g. `*.openai.com` for secret injection as well as network call filtering.

by afshinmeh

4/1/2026 at 7:04:36 PM

You know, the thing is, that it is super easy to create such tools with AI nowadays. …and if you create your own, you can avoid these unnecessary abstractions. You get exactly what you want.

by mdavid626

4/1/2026 at 6:47:55 PM

How do you intercept network traffic on mac os? How do you fake certificates?

by mdavid626

4/1/2026 at 7:04:03 PM

Zerobox creates a cert in `~/.zerobox/cert` on the first proxy run and reuses that. The MTIM process uses that cert to make the calls, inject certs, etc. This is actually done by the underlying Codex crate.

by afshinmeh

4/1/2026 at 7:06:05 PM

Yeah, but how does the sandboxed process “know” that it has to go through the proxy? How does it trust your certificate? Is the proxy fully transparent?

by mdavid626

4/1/2026 at 7:09:37 PM

Oh I see. It inject HTTP_PROXY/HTTPS_PROXY/etc. env vars into the process so that all sandboxed subprocesses go through the proxy.

by afshinmeh

4/1/2026 at 7:24:04 PM

What if the program doesn’t respect those env vars? Can Zerobox still block network calls in that case?

by blanched

4/1/2026 at 7:50:39 PM

Great question! On Linux, yes, network namespaces enforce that and all net traffic goes through the proxy. Direct connections are blocked at the kernel level even if the program ignores proxy env vars, but I will test this case a bit more (unsure how to though, most network calls would respect HTTPS_PROXY and other similar env vars).

That being said, the default behaviour is no network, so nothing will be routed if it's not allowed regardless of whether the sandboxed process respects env vars or not.

by afshinmeh

4/1/2026 at 8:04:04 PM

How about on macOS?

by simonw

4/1/2026 at 8:08:42 PM

On macOS, the proxy is best effort. Programs that ignore HTTPS_PROXY/HTTP_PROXY can connect directly. This is a platform limitation (macOS Seatbelt doesn't support forced proxy routing).

BUT, the default behaviour (no net) is fully enforced at the kernel level. Domain filtering relies on the program respecting proxy env vars.

by afshinmeh

4/1/2026 at 8:12:46 PM

I thought seatbelt-exec had mechanisms for that?

  (allow network-outbound
    (remote tcp "127.0.0.1:8080"))

by simonw

4/1/2026 at 8:21:32 PM

It does but because I'm inheriting the seatbelt settings from Codex, I'm not resetting it in Zerobox (I thought it's a safer option). Let me look into this, there should be a way to take Codex' profile and safely combine/modify it.

by afshinmeh

4/1/2026 at 9:45:33 PM

Does Zerobox support audit logging for blocked network or file operations?

by mina_jamshidian

4/1/2026 at 10:09:27 PM

I added some basic --debug support earlier today, but I will work on proper JSONL/Otel integration soon.

by afshinmeh

4/1/2026 at 8:18:55 PM

Very cool. Is there a way to have a notion of a session, saving state between runs?

by dk8996

4/1/2026 at 8:19:57 PM

No, it's stateless right now. What is your requirement though? How do you define a session? Are you referring to "snapshotting" between sessions?

by afshinmeh

4/1/2026 at 5:30:10 PM

Cool project, and I think there would be a lot of value in just logging all operations.

by alyxya

4/1/2026 at 5:49:27 PM

For just logging would it really give any more info than a trace already does?

by kimixa

4/1/2026 at 6:40:36 PM

Forgot about that, was mostly thinking about how AI agents with unrestricted permissions would ideally have some external logging and monitoring, so there would be a record of what it touched. A trace has all of the raw information, so some kind of wrapper around that would be useful.

by alyxya

4/1/2026 at 6:45:16 PM

I'd like to know what level of details you'd expect. Something like `zerobox -- claude`, then you get an output log like this:

```

Read file /etc/passwd

Made network call to httpbin.org

Write file /tmp/access

```

etc.? I'm really interested to hear your thoughts and I will add that feature (I need something like that, too).

by afshinmeh

4/1/2026 at 9:45:30 PM

*strace that is - annoyingly it seems it was autocorrected away

by kimixa

4/1/2026 at 9:53:58 PM

I think there is still a valid case for sandbox logs/otel. strace would give you the syscalls/traces but not _why_ a particular call was blocked in side the sandbox (e.g. the decision making bit).

by afshinmeh

4/1/2026 at 6:07:14 PM

Agreed. I added the `--debug` flag this morning. It does simple logging including the proxy calls:

```

$ zerobox --debug --allow-net=httpbin.org -- curl

2026-04-01T18:06:33.928486Z CONNECT blocked (client=127.0.0.1:59225, host=example.com, reason=not_allowed)

curl: (56) CONNECT tunnel failed, response 403

```

I'm planning on adding otel integration as well.

by afshinmeh

4/2/2026 at 3:06:33 AM

I love sandboxes man

by DanDeBugger

4/1/2026 at 8:26:27 PM

Wish it wasn’t rust… it’s so hard to read.

by Lethalman

4/1/2026 at 9:06:40 PM

I know. I will add more docs soon though, that should make it easier to navigate the code and understand what's going on.

by afshinmeh

4/1/2026 at 7:06:24 PM

This is more a criticism of codex's linux-sandboxing, which you're just wrapping, but it's the first I've ever looked at it. I don't see how it makes sense to invoke bwrap as a forked subprocess. Bubblewrap can't do anything beyond what you can do with unshare directly, which you can simply invoke as a system call without needing to spawn a subprocess or requiring the user to have bwrap installed. It kinds of reeks of amateur hour when developers effectively just translate shell scripts into compiled languages by using whatever variant of "system" is available to make the same command invocations you would make through a shell, as opposed to actually using the system call API. Especially when the invocation is crafted from user input, there's a long history of exploits arising from stuff like this. Writing it in Rust does nothing for you when you're just using Rust to call a different CLI tool that isn't written in Rust.

by nonameiguess

4/1/2026 at 8:09:09 PM

Is your criticism here that there's no point in invoking bwrap directly when you could instead implement the same things that bwrap implements?

I'd much rather a system call bwrap than re-implement bwrap, because bwrap has already been extensively tested.

by simonw

4/1/2026 at 8:43:15 PM

That was my thinking, too. The only other option would be reimplement it in Rust (never researched what exists though).

by afshinmeh

4/1/2026 at 7:22:38 PM

Thanks for sharing this, I read your comment multiple times. What would be the alternative though? It is true that the program being written in Rust doesn't solve the problem of spawning subprocesses, but what's the alternative in that case?

by afshinmeh

4/1/2026 at 7:53:58 PM

This is really useful! How well does it compare though to Docker etc.

Because I am worried about sandbox escapes. This is what we currently use to sandbox JS inside Browsers and Node (without anything extra) : https://github.com/Qbix/Platform/blob/main/platform/plugins/...

I like tools like this, but they all seem to share the same underlying shape: take an arbitrary process and try to restrict it with OS primitives + some policy layer (flags, proxies, etc).

That works, but it also means correctness depends heavily on configuration, i.e. you’re starting with a lot of ambient authority and trying to subtract from it enforcement ends up split across multiple layers (kernel, wrapper, proxy)

An alternative model is to flip it: Instead of sandboxing arbitrary programs, run workflows in an environment where there is no general network/filesystem access at all, and every external interaction has to go through explicit capabilities.

In that setup, there’s nothing to "block" because the dangerous primitives aren’t exposed, execution can be deterministic/replayable, so you can actually audit behavior. Thus, secrets don’t enter the execution context, they’re only used at the boundary

It feels closer to capability-based systems than traditional sandboxing. Curious how people here think about that tradeoff vs OS-level sandbox + proxy approaches.

by EGreg

4/1/2026 at 8:00:12 PM

Zerobox uses the same kernel mechanisms (namespaces + seccomp) but no daemon, no root and cold start ~10ms (Docker is much worse in that regard).

Docker gives you full filesystem isolation and resource limits. Zerobox gives you granular file/network/credential controls with near zero overhead. You can in fact use Zerobox _inside_ Docker (e.g. for secret management)

by afshinmeh

4/1/2026 at 7:25:47 PM

there's been so many of these -- which of these sandboxing tools is best?

by gigatexal

4/1/2026 at 7:40:21 PM

Not a single one. All of them are solving the obvious (and wrong) problem.

by _pdp_

4/1/2026 at 8:03:32 PM

What's the right problem to be solving here?

by simonw

4/1/2026 at 8:01:34 PM

I'd love to learn more please. I'm interested in sandboxing AI tools/agents regardless of the underlying mechanism (I explored Firecracker VMs briefly as well, terrible cross platform support though).

by afshinmeh

4/1/2026 at 6:20:08 PM

[flagged]

by volume_tech

4/1/2026 at 6:22:49 PM

Thanks and agreed! Zerobox uses the Deno sandboxing policy and also the same pattern for cred injection (placeholders as env vars, replaced at network call time).

Real secrets are never readable by any processes inside the sandbox:

```

zerobox -- echo $OPENAI_API_KEY

ZEROBOX_SECRET_a1b2c3d4e5...

```

by afshinmeh

4/1/2026 at 6:28:08 PM

Do you know if there's a widely shared name for this pattern? I've been collecting examples of it recently - it's a really good idea - but I'm not sure if there's good terminology. "Credential injection" is one option I've seen floating around.

by simonw

4/1/2026 at 7:42:16 PM

simonw, I have been seeing "credential injection" and "credential tokenizing" (a la tokenizer: https://github.com/superfly/tokenizer). I'm also seeing credential "surrogates" mentioned.

I am currently working on a mitm proxy for use with devcontainers to try to implement this pattern, but I'm certainly not the only one!

by TheTaytay

4/1/2026 at 8:06:58 PM

Thanks, I think I'll go with "credential injection" since the word "tokenization" has other meanings that I find confusing here.

by simonw

4/2/2026 at 1:55:37 AM

I agree, but I don’t love the negative connotations of “Injection” in this space!

by TheTaytay

4/2/2026 at 2:55:24 AM

"Credential proxy pattern" might work.

by simonw

4/1/2026 at 6:39:51 PM

Not sure. I took this idea from the Deno sandboxing docs. They also do the exact same thing, different sandboxing mechanism though (I think Deno has it's own way of sandboxing subprocesses).

by afshinmeh

4/1/2026 at 8:58:52 PM

[flagged]

by gbibas

4/1/2026 at 11:05:20 PM

Clearly a bot. Leave. Not allowed under site rules.

by sebmellen

4/2/2026 at 1:45:35 AM

Nope, just a guy who's been lurking since 2011 and finally has opinions. I'll work on being less organized about it.

by gbibas

4/2/2026 at 3:55:30 AM

[dead]

by Mooshux

4/1/2026 at 7:28:21 PM

[dead]

by MarcelinoGMX3C