7/12/2026 at 3:31:10 AM
I always separate the coding tools from LLM providers, and use bubblewrap to sandbox the coding tools so they:1. Can only read the working project directory, with .git read-only and sensitive directories hidden (mounted as empty directories).
2. Have an isolated network namespace; they can only access the internet through an HTTP proxy hosted on a Unix socket, can only access specific LLM provider hostnames, and exclude the tool's own hostname.
For example, with Crush, I will let it access *.openrouter.ai (LLM providers) but not *.charm.land (Crush's domain for auto-updating the LLM list).
This makes me feel much more comfortable enabling "yolo" mode and letting the tools do everything.
by phaseleza
7/12/2026 at 4:13:05 AM
with bubblewrap it's better to pull a rootfs from dockerhub (eg. debian:unstable) then bootstrap it into a fully fledged distro rootfs living in its own folder. install the AI agents right into it, then create launch scripts that invoke bwrap with the distro rootfs (readonly) and a custom read-write /home/user and run whatever you want inside it - it will not see anything important outside the directory you give it. you can also run multiple agents each invisible to the others.for bonus points you can uplift the bwrap container into an actual sandbox by invoking gvisor (`runsc ... do ...`) from inside it, or a virtual machine monitor like muvm. I'm really fond of this pattern because you can trust bwrap to set up the environment, then you just need a sandbox tool to lock it down.
bwrap by itself will probably be sufficient against most adversaries as assuming proper config it would require committing to using a linux kernel 0day to escalate privs.
by teravor
7/12/2026 at 6:14:02 AM
Thanks for the suggestions. I've used debootstrap to build a Debian rootfs for bwrap before, but my threat model is simpler: nothing sensitive lives outside $HOME on my machine. So I just ro-bind the system dirs I need and give the sandbox a tmpfs home (one-shot apps) or a persistent fake home (stateful apps, under ~/.var/app/<appname>). This is good enough for my case.The gvisor layering looks promising though. I'll take a look and see if it would be useful.
by phaseleza
7/13/2026 at 6:56:49 AM
+1 for bubblewrap, unsharing everything and then adding back everything your agent needs saves the trouble of updating a docker image and allows you to give selective access to local tooling. I actually go as far as to run nearly every. single. application. in bwrap that doesn't come with native sandboxing. I share credential authentication via sockets, had to build custom schemas for k8s and docker since they still don't have a way to do remote attestation...by himata4113
7/14/2026 at 3:42:34 AM
This is the way.For CC I have a template here https://kaveh.page/blog/claude-code-sandbox
by kwar13
7/12/2026 at 4:17:09 AM
What's your mechanism for doing this?by timr
7/12/2026 at 6:15:19 AM
I use bubblewrap to unshare all namespaces (net, pid, ipc, user) and ro-bind necessary system paths like /etc, /lib, create a tmpfs home, mount the project folder under it (writable), then mount tmpfs over sensitive directories inside the project to hide them.For the network part, a daemon outside the sandbox serves a filtering HTTP proxy on a Unix socket. I mount the Unix socket into the sandbox and bridge it to localhost with socat. With the net namespace unshared, the app can't reach the network at all except through this proxy, which only allows LLM providers.
By separating the coding tool from the LLM provider, I feel safer: the coding tool cannot leak anything on its own. It can only talk to the LLM provider, so a real leak would require the provider to be complicit too. And any sensitive files, inside or outside the project, are hidden by the mount namespace, which I suppose is hard to escape.
by phaseleza
7/12/2026 at 8:59:08 PM
> I mount the Unix socket into the sandbox and bridge it to localhost with socatI was experimenting with network sandboxing and found a solution that doesn't require an agent inside a sandbox. You can create listening socket on localhost inside the sandbox, send it over the Unix socket to the supervisor outside and close the Unix socket. The supervisor outside now has a listening socket that accepts connections from inside. No socat needed.
My setup was more complicated though, I wanted transparent proxying (intercepting every TCP/UDP connection without having to specify a proxy) and I spent 2 nights fighting with lack of documentation on netfilter. For TCP I ended up with creating a listening socket with IP_TRANSPARENT options and tproxy'ing all traffic into it using nftables. It was easy part. The difficult part was to figure out how to intercept UDP datagrams and send replies with correct sender address. I ended up creating IP_TRANSPARENT listening UDP socket to receive datagrams, and raw IP socket to send replies with forged source address (because single UDP socket doesn't allow sending datagrams from arbitrary port number).
ChatGPT was pretty much useless, probably due to lack of documentation and I had to experiment myself.
I still do not have the supervisor done though, that would decide whether to allow or block a connection. I have the following idea: whenever the target makes a DNS request, I reply with a new IP address like 10.x.x.x. So I can have a map which maps every IP address to a domain, and when a program connects to an IP, I can figure out which domain it is and decide whether allow or block it. This is necessary because there might be multiple IPs for a domain, they can change in time, so it is better to have a persistent mapping, to protect from DNS rebinding attacks.
by codedokode
7/13/2026 at 7:45:49 AM
My colleague implemented your idea of assigning fake IPS to hostnames to allow hostname filtering. It works great.by Zentrik
7/12/2026 at 9:38:02 AM
Think they are referring to this https://github.com/containers/bubblewrapby khurs
7/13/2026 at 5:40:56 AM
This achieves much the same thing but using docker, not bubblewrap. `byre develop` drops you into your agent in a sandbox with the current folder mounted. Enabling the firewall or mounting other folders is a few seconds in `byre config` (although you can also switch the firewall on by default). https://github.com/pjlsergeant/byreby petesergeant
7/13/2026 at 4:14:12 AM
This is an option:by cowpig
7/12/2026 at 12:28:23 PM
> This makes me feel much more comfortable enabling "yolo" mode and letting the tools do everything.But is this only a feelings thing, or did this additional hardening ever actually catch something nasty?
I find that models that do really dumb shit where constraints pay off are models not worth using in general.
Not a knock on the practice, I'm in the process of hardening my own stuff too, just curious.
by perching_aix