upvote
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.

reply
> I mount the Unix socket into the sandbox and bridge it to localhost with socat

I 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.

reply
Think they are referring to this https://github.com/containers/bubblewrap
reply