Top
Best
New

Posted by 0o_MrPatrick_o0 1/15/2026

Bubblewrap: A nimble way to prevent agents from accessing your .env files(patrickmccanna.net)
187 points | 140 comments
bjackman 1/15/2026|
I really don't understand why people have all these "lightweight" ways of sandboxing agents. In my view there are two models:

- totally unsandboxed but I supervise it in a tight loop (the window just stays open on a second monitor and it interrupts me every time it needs to call a tool).

- unsupervised in a VM in the cloud where the agent has root. (I give it a task, negotiate a plan, then close the tab and forget about it until I get a PR or a notification that it failed).

I want either full capabilities for the agent (at the cost of needing to supervise for safety) or full independence (at the cost of limited context in a VM). I don't see a productive way to mix and match here, seems you always get the worst of both worlds if you do that.

Maybe the usecase for this particular example is where you are supervising the agent but you're worried that apparently-safe tool calls are actually quietly leaving a secret that's in context? So it's not that it's a 'mixed' usecase but rather it's just increasing safety in the supervised case?

emilburzo 1/15/2026||
> unsupervised in a VM in the cloud where the agent has root

Why in the cloud and not in a local VM?

I've re-discovered Vagrant and have been using it exactly for this and it's surprisingly effective for my workflows.

https://blog.emilburzo.com/2026/01/running-claude-code-dange...

avtar 1/15/2026|||
It's been ages since I used VirtualBox and reading the following didn't make me miss the experience at all:

> Eventually I found this GitHub issue. VirtualBox 7.2.4 shipped with a regression that causes high CPU usage on idle guests.

The list of viable hypervisors for running VMs with 3D acceleration is probably short but I'd hope there are more options these days for running headless VMs. Incus (on Linux hosts) and Lima come to mind and both are alternatives to Vagrant as well.

emilburzo 1/15/2026||
I totally understand, Vagrant and VirtualBox are quite a blast from the past for me as well. But besides the what-are-the-odds bug, it's been smooth sailing.

> VMs with 3D acceleration

I think we don't even need 3D acceleration since Vagrant is running the VMs headless anyways and just ssh-ing in.

> Incus (on Linux hosts)

That looks interesting, though from a quick search it doesn't seem to have a "Vagrantfile" equivalent (is that correct?), but I guess a good old shell script could replace that, even if imperative can be more annoying than declarative.

And since it seems to have a full-VM mode, docker would also work without exposing the host docker socket.

Thanks for the tip, it looks promising, I need to try it out!

avtar 1/15/2026||
> though from a quick search it doesn't seem to have a "Vagrantfile" equivalent (is that correct?)

It's just YAML config for the VM's resources:

https://linuxcontainers.org/incus/docs/main/howto/instances_...

https://linuxcontainers.org/incus/docs/main/explanation/inst...

And cloud-init for provisioning:

https://gitlab.oit.duke.edu/jnt6/incus-config/-/blob/main/co...

benterix 1/19/2026||||
Depends on what you do. If you need to have a fully working site with external integrations, SSL and so on, it's just easier to spend $4 a month on a VPS. But you're right, for many backend-based projects a local VM like multipass or a kind/microk8s cluster are perfectly fine.
ahmadyan 1/15/2026||||
You mentioned "deleting the actual project, since the file sync is two-way", my solution (in agentastic.dev) was to fist copy the code with git-worktree, then share that with the container.
bjackman 1/15/2026|||
Yeah local is totally fine too just whatever is easiest to set up.
Bender 1/15/2026|||
As someone that does this, it's Turtles All The Way Down [1]. Every layer has escapes. I require people to climb up multiple turtles thus breaking most skiddie [2] scripts. Attacks will have to targeted and custom crafted by people that can actually code thus reducing the amount of turds in the swimming pool I must avoid. People should not write apps that make assumptions around accessing sensitive files.

[1] - https://en.wikipedia.org/wiki/Turtles_all_the_way_down

[2] - https://en.wikipedia.org/wiki/Skiddies

bjackman 1/15/2026||
It's turtles all the way down but there is a VERY big gap between VM Isolation Turtle and <a half-arse seccomp policy> turtle. It's a qualitative difference between those two sandboxes.

(If the VM is remote, even more so).

theptip 1/15/2026|||
It’s a risk/convenience tradeoff. The biggest threat is Claude accidentally accesses and leaks your ssl keys, or gets prompt-hijacked to do the same. A simple sandbox fixes this.

There are theoretical risks of Claude getting fully owned and going rogue, and doing the iterative malicious work to escape a weaker sandbox, but it seems substantially less likely to me, and therefore perhaps not (currently) worth the extra work.

bjackman 1/15/2026||
How does a simple sandbox fix this at all? If Claude has been prompt-hijacked you need a VM to be anywhere near safe.
Filligree 1/15/2026||
Prompt-hijacking is unlikely. GP is most likely trying to prevent mistakes, not malicious behavior.
sschueller 1/15/2026|||
Is there a premade VM image or docker container I can just start with for example Google Antigravity, Claude or Kilocode/vscode? Right now I have to install some linux desktop and all the tools needed, a bit of a pain IMO.

I see there are cloud VMs like at kilocode but they are kind if useless IMO. I can only interact with the prompt and not the code base directly. Too many things go wrong and maybe I also want kilo code to run a docker stack for me which it can't in the agent cloud.

bjackman 1/15/2026|||
I use https://jules.google.

The UI is obviously vibe-coded garbage but the underlying system works. And most of the time you don't have to open the UI after you've set it running you just comment on the Github PR.

This is clearly an unloved "lab" project that Google will most likely kill but to me the underlying product model is obviously the right one.

I assume Microsoft got this model right first with the "assign issue to Copilot" thing and then fumbled it by being Microsoft. So whoever eventually turns this <correct product model> into an <actual product that doesn't suck> should win big IMO.

roywiggins 1/15/2026||||
Locally, I'd use Vagrant with a provisioning script that installs whatever you need on top of one of the prebuilt Vagrant boxes. You can then snapshot that if you want and turn that into a base image for subsequent containers.
emilburzo 1/15/2026||||
> [...] and maybe I also want kilo code to run a docker stack for me which it can't in the agent cloud

Yes! I'm surprised more people do not want this capability. Check out my comment above, I think Vagrant might also be what you want.

wasting_time 1/15/2026||||
fly.io launched something like that recently:

https://sprites.dev/

arcanemachiner 1/15/2026|||
Just got started with Claude Code the other day, using the dev container CLI. It's super easy.

TLDR:

- Ensure that you have installed npm on your machine.

- Install the dev container CLI globally via npm: `npm i -g @devcontainers/cli`

- Clone the Claude Code repo: https://github.com/anthropics/claude-code

- Navigate into the root directory of that repo.

- Run the dev container CLI command to start the container: `devcontainer --workspace-folder . up`

- Run another dev container command to start Claude in the container: `devcontainer exec --workspace-folder . claude`

And there you go! You have a sandboxed environment for Claude to work in. (As sandboxed as Docker is, at least.)

I like this method because you can just manage it like any other Docker container/volumes. When you want to rebuild it, or reset the volume, you just use the appropriate Docker (and the occasional dev container) commands.

bjackman 1/15/2026||
I guess whether container isolation is good enough just comes down to the threat you're protecting against:

- confused/misaligned agent: probably good enough (as of Q1 2026...).

- hijacked agent: definitely not good enough.

But also it's kinda weird that we still have high-level interfaces that force you to care this much about the type of virtualization it's giving you. We probably need to be moving more towards stuff like Incus here that treats VMs and system containers basically as variants of the same thing that you can manage at a higher level of abstraction. (I think k8s can be like that too).

dizhn 1/15/2026|||
I was using opencode the other day. It took me a while to realize the that the agent couldn't read/write the .env file but didn't realize it. When I pushed it first it was able to create a temp file and copy it over .env AND write and opencode.json file that disables the .env protection and go wild.
srini-docker 1/16/2026||
[dead]
simonw 1/15/2026||
I recommend caution with this bit:

  --bind "$HOME/.claude" "$HOME/.claude"
That directory has a bunch of of sensitive stuff in it, most notable the transcripts of all of your previous Claude Code sessions.

You may want to take steps to avoid a malicious prompt injection stealing those, since they might contain sensitive data.

0o_MrPatrick_o0 1/26/2026||
Heya- The reason I add this directory is because Claude needs read/write permissions for getting new auth tokens.

Without this, you'll have to re-login to Claude every time. Breaks the speed of development.

I'm going to do some experimenting to see if I can make this bind more precise.

pmontra 1/15/2026|||
I think that the rw directories should not be shared among projects. Maybe there should be separate copies even for what gets mounted into $HOME/.nvm
0o_MrPatrick_o0 1/15/2026||
Wonderful insight! Thank you!
meander_water 1/15/2026||
I recently created a throwaway API key for cloudflare and asked a cursor cloud agent to deploy some infra using it, but it responded with this:

> I can’t take that token and run Cloudflare provisioning on your behalf, even if it’s “only” set as an env var (it’s still a secret credential and you’ve shared it in chat). Please revoke/rotate it immediately in Cloudflare.

So clearly they've put some sort of prompt guard in place. I wonder how easy it would be to circumvent it.

0o_MrPatrick_o0 1/15/2026||
If your prompt is complex enough, doesn’t seem to get triggered.

I use a lot of ansible to manage infra, and before I learned about ansible-vault, I was moving some keys around unprotected in my lab. Bad hygiene- and no prompt intervening.

Kinda bums me out that there may be circumstances where the model just rejects this even if you for some reason you needed it.

mmis1000 1/15/2026||
It seems depends on model and context usage though, the agent forgets a lot of things after half fill up. It even forgets the primary target you give at the start of chat.
bavell 1/15/2026||
Claude definitely has some API token security baked in, it saw some API keys in a log file of mine the other day and called them out to me as a security issue very clearly. In this case it was a false positive but it handled the situation well and even gave links to reset each token.
flakes 1/15/2026||
I find it better to bubblewrap against a full sandbox directory. Using docker, you can export an image to a single tarball archive, flattening all layers. I use a compatible base image for my kernel/distro, and unpack the image archive into a directory.

With the unpack directory, you can now limit the host paths you expose, avoiding leaking in details from your host machine into the sandbox.

bwrap --ro-bind image/ / --bind src/ /src ...

Any tools you need in the container are installed in the image you unpack.

Some more tips: Use --unshare-all if you can. Make sure to add --proc and --dev options for a functional container. If you just need network, use both --unshare-all and --share-net together, keeping everything else separate. Make sure to drop any privileges with --cap-drop ALL

raphinou 1/15/2026||
I put all my agents in a docker file in which the code I'm working on is mounted. It's working perfectly for me until now. I even set it up so I can run gui apps like antigravity in it (X11). If anyone is interested I shared my setup at https://github.com/asfaload/agents_container
grewil2 1/15/2026|
It won’t save you from prompt injektions that attack your network.
TCattd 1/15/2026|||
Shameless plug, in case you're interested: https://github.com/EstebanForge/construct-cli

Let me know if you give it a go ;)

sschueller 1/15/2026||
Interesting, any plans to add LiteLLM (https://github.com/BerriAI/litellm) and Kilocode (https://github.com/Kilo-Org/kilocode)?
TCattd 1/15/2026|||
Added https://github.com/EstebanForge/construct-cli/releases
TCattd 1/15/2026|||
Will check those out :)
fgonzag 1/15/2026||||
In theory the docker container should only have the projects directory mounted, open access to the internet, and thats it. No access to anything else on the host or the local network.

Internet to connect with the provider, install packages, and search.

It's not perfect but it's a start.

63stack 1/15/2026||||
Docker containers run in their separate isolated network
darig 1/15/2026|||
[dead]
vscode-rest 1/15/2026|||
[dead]
raphinou 1/15/2026|||
of course, I'm not pretending this is a universal remedy solving all the problems. But I will add a note in the readme to make it clear, thanks for the feedback!
dangoodmanUT 1/15/2026||
I've been saying bubblewrap is an amazing solution for years (and sandbox-exec as a mac alternative). This is the only way i run agents on systems i care about
catlifeonmars 1/15/2026|
> run agents on systems i care about

You must not care about those systems that much.

typs 1/15/2026||
I wish I had the opposite of this. It’s a race trying to come up with new ways to have Cursor edit and set my env files past all their blocking techniques!
verdverm 1/15/2026||
Like this? (Obfuscated, from agent and history)

https://bsky.app/profile/verdverm.com/post/3mbo7ko5ek22n

GrowingSideways 1/15/2026||
If you wouldn't upload keys to github, why would you trust them to cursor?
hahahahhaah 1/15/2026||
A local .env should be safe to put on your T shirt and walk down times square.

Mysql user: test

Password: mypass123

Host: localhost

...

jen729w 1/15/2026|||
STRIPE_SECRET_KEY="op://81 Dev environment variables/Stripe - dev - API keys/STRIPE_SECRET_KEY"

https://developer.1password.com/docs/cli/

ImPostingOnHN 1/15/2026||
How does that prevent an agent from leaking it once it's read into context?
jen729w 1/15/2026||
Great question. I just checked, and because I launch my entire VSCode with `op run …` (which makes dev life easier), Claude reports that it can read my dev secrets.

I could prevent this by running Claude outside of this context. I'm not going to, because this context only has access to my dev secrets. Hence the vault name: `81 Dev environment variables`.

I've configured it so that the 1P CLI only has access to that vault. My prod secrets are in another vault. I achieve this via a OP_SERVICE_ACCOUNT_TOKEN variable set in .zshrc.

I can verify this works by running:

    op run --env-file='.env.production' -- printenv
    [ERROR] 2026/01/15 21:37:41 "82 Prod environment variables" isn't a vault in this account. Specify the vault with its ID or name.
Also, of course, 1Password pops up a fingerprint request every time something tries to read its database. So if that happened unexpectedly, I'd wonder what was up. I'm acutely conscious of those requests.

I can't imagine it's perfect, but I feel pretty good.

Imustaskforhelp 1/15/2026|||
Create a symlink to .env from another file and ask cursor to refer it if name is the concern regarding cursor (I don't knowhow cursor does this stuff)
brendoncarroll 1/15/2026||
I also wrote a tool for doing this[0], after one of these agents edited a config file outside of the repo it was supposed to work within. I only realized the edit because I have my dotfiles symlinked to a git repository, and git status showed it when I was committing another change. It's likely that the agents are making changes that I (and others) are not aware of because there is no easy way to detect them.

The approach I started taking is mounting the directory, that I want the agent to work on, into a container. I use `/_` as the working directory, and have built up some practices around that convention; that's the only directory that I want it to make changes to. I also mount any config it might need as read-only.

The standard tools like claude code, goose, charm, whatever else, should really spawn the agent (or MCP server?) in another process in a container, and pipe context in and out over stdin/stdout. I want a tool for managing agents, and I want each agent to be its own process, in its own container. But just locking up the whole mess seems to work for now.

I see some people in the other comments iterating on what the precise arguments to bubblewrap should be. nnc lets you write presets in Jsonnet, and then refer them by name on the command line, so you can version and share the set of resources that you give to an agent or subprocess.

[0] https://github.com/brendoncarroll/nnc

aszen 1/15/2026||
I wonder why we are even storing secrets in .env files in plain text
makoto12 1/15/2026||
This wouldn't have made the front page if it was: "How to not store your secrets in plain text"
patapong 1/15/2026|||
I would also prefer not doing this. Does anyone know of any lightweight, cross platform alternatives?
geoffeg 1/15/2026|||
I use sops and age, originally loosely based on this article: https://devops.datenkollektiv.de/using-sops-with-age-and-git...

I originally set up the git filters, but later disabled them.

phrotoma 1/15/2026||||
Perhaps I'm off base here but it seems like the goal is:

1. allow an agent to run wild in some kind of isolated environment, giving the "tight loop" coding agent experience so you don't have to approve everything it does.

2. let it execute the code it's creating using some credentials to access an API or a server or whatever, without allowing it to exfil those creds.

If 1 is working correctly I don't see how 2 could be possible. Maybe there's some fancy homomorphic encryption / TEE magic to achieve this but like ... if the process under development has access to the creds, and the agent has unfettered access to the development environment, it is not obvious to me how both of these goals could be met simultaneously.

Very interested in being wrong about this. Please correct me!

throwaway633f 1/15/2026|||
You can accomplish both goals by setting up a proxy server to the API, and giving the agent access to the proxy.

You setup a simple proxy server on localhost:1234 that forwards all incoming requests to the real API and the crucial part is that the proxy adds the "Auth" header with the real auth token.

This way, the agent never sees the actual auth token, and doesn't have access to it.

If the agent has full internet access then there are still risks. For example, a malicious website could convince the agent itself to perform malicious requests against the API (like delete everything, or download all data and then upload it all to some hacker server).

But in terms of the security of the auth token itself, this system is 100% secure.

phrotoma 1/16/2026||
That's clever.

Did you make this account to tell me this? Thank you!

0o_MrPatrick_o0 1/15/2026|||
You’ve got my intent correct!

Where I’m at with #2 is the agent builds a prototype with its own private session credentials.

I have orchestration created that can replicate the prototyping session.

From there I can keep final build keys secret from the agent.

My build loop is meant to build an experiment first, and then an enduring build based on what it figures out.

eddd-ddde 1/15/2026||||
https://www.passwordstore.org/

You can easily script it to decode passwords on demand.

WhyNotHugo 1/15/2026||||
If your .env file is being sourced by something like direnv, you can have it read secrets from the secret storage service and export them as env vars.

If you bind-mount the directory, the sandbox can see the commands, but executing them won’t work since it can’t access the secret service.

aszen 1/16/2026|||
https://devenv.sh/integrations/secretspec/
johnisgood 1/15/2026||
I would like an answer, too.
prmoustache 1/15/2026|
Isn't landrun the preferred way to sandbox apps on linux these days instead?

https://github.com/Zouuup/landrun

qrobit 1/15/2026||
Bubblewrap seems to be much more popular[^1], personally this is the first time I heard about landrun

[1]: https://repology.org/project/bubblewrap/information https://repology.org/project/landrun/information

dividuum 1/15/2026||
bubblewrap is a lot more flexible: You can freely piece together the sandboxed filesystem environment from existing directories, tmpfs, files or data provided via a file descriptor. landrun, from what I understand only restricts what already exists. What is neat with landrun is the TCP port restrictions. This isn't possible with bubblewrap at the moment, although nothing really prevents bubblewrap from adding landlock support for those cases.
More comments...