Sandboxing AI Agents in Linux

Published: (February 3, 2026 at 12:35 PM EST)
3 min read

Source: Hacker News

Sandboxing

The standard solution is to sandbox the agent – either on a remote machine (exe.dev, sprites.dev, daytona.io), or locally via Docker or other virtualization mechanisms.

A lightweight alternative on Linux is bubblewrap, which uses Linux kernel features like cgroups and user namespaces to limit (jail) a process.

As it turns out, bubblewrap is a good solution for lightweight sandboxing of AI agents. Here’s what I personally need from such a solution:

  • Mimic my regular Linux dev machine setup (I don’t want to manage multiple dev environments).
  • Minimal/no access to information outside what’s required for the current project.
  • Write access only to the current project.
  • Direct operation on the files/folders of the project so I can easily inspect or modify the same files from my IDE or run the code myself.
  • Network access – both to connect to AI providers and search the internet, and to be able to start a server that I can connect to.

Bubblewrap and Docker are not hardened security isolation mechanisms, but that’s okay with me. I’m not really concerned about the following risks:

  • Escape via zero‑day Linux kernel bug.
  • Covert side‑channel communications.
  • Exfiltration of data from the current project (including project‑specific access keys).
  • Screwing up the codebase (the code is managed via git and backed up at GitHub or elsewhere).

An alternative is to contain potential damage by creating project‑specific API keys so at least the blast area is minimal if those keys are leaked.

In practice

Here’s how my bubblewrap sandbox script looks:

#!/usr/bin/bash

exec 3<$HOME/.claude.json

exec /usr/bin/bwrap \
    --tmpfs /tmp \
    --dev /dev \
    --proc /proc \
    --hostname bubblewrap --unshare-uts \
    --ro-bind /bin /bin \
    --ro-bind /lib /lib \
    --ro-bind /lib32 /lib32 \
    --ro-bind /lib64 /lib64 \
    --ro-bind /usr/bin /usr/bin \
    --ro-bind /usr/lib /usr/lib \
    --ro-bind /usr/local/bin /usr/local/bin \
    --ro-bind /usr/local/lib /usr/local/lib \
    --ro-bind /opt/node/node-v22.11.0-linux-x64/ /opt/node/node-v22.11.0-linux-x64/ \
    --ro-bind /etc/alternatives /etc/alternatives \
    --ro-bind /etc/resolv.conf /etc/resolv.conf \
    --ro-bind /etc/profile.d /etc/profile.d \
    --ro-bind /etc/bash_completion.d /etc/bash_completion.d \
    --ro-bind /etc/ssl/certs /etc/ssl/certs \
    --ro-bind /etc/ld.so.cache /etc/ld.so.cache \
    --ro-bind /etc/ld.so.conf /etc/ld.so.conf \
    --ro-bind /etc/ld.so.conf.d /etc/ld.so.conf.d \
    --ro-bind /etc/localtime /etc/localtime \
    --ro-bind /usr/share/terminfo /usr/share/terminfo \
    --ro-bind /usr/share/ca-certificates /usr/share/ca-certificates \
    --ro-bind /etc/nsswitch.conf /etc/nsswitch.conf \
    --ro-bind /etc/hosts /etc/hosts \
    --ro-bind /etc/ssl/openssl.cnf /etc/ssl/openssl.cnf \
    --ro-bind /usr/share/zoneinfo /usr/share/zoneinfo \
    --ro-bind $HOME/.bashrc $HOME/.bashrc \
    --ro-bind $HOME/.profile $HOME/.profile \
    --ro-bind $HOME/.gitconfig $HOME/.gitconfig \
    --ro-bind $HOME/.local $HOME/.local \
    --bind $HOME/.claude $HOME/.claude \
    --bind $HOME/.cache $HOME/.cache \
    --file 3 $HOME/.claude.json \
    --bind "$PWD" "$PWD" \
    claude --dangerously-skip-permissions "$@"

If this looks rather idiosyncratic, it’s because it is. Rather than using generic rules, I experimented with bwrap until I found the minimal configuration needed for my system.

Some interesting details

  • /tmp, /proc and /dev are automatically handled by bwrap.
  • I bind‑mount (i.e., expose) files and directories under the same path as on the local machine, so there’s no difference in file locations or project paths.
  • I don’t expose the entire /etc, only the bare minimum required.
  • The content of $HOME/.claude.json is injected into the sandbox, so any changes there won’t affect the real file.
  • The $HOME/.claude/ directory is mapped read‑write, allowing Claude to save session data.
  • /opt/node/node-v22.11.0-linux-x64/ is my custom Node.js installation location.
  • Changing the hostname makes it easy to distinguish between the host and the sandbox.

I’ll probably tweak the script as needed, but this is a solid starting point for me.

How to customize

If you want to adapt this to another AI agent or to your system, my suggestion is to modify the script to run bash instead, then launch your agent manually, observe what breaks, and adjust accordingly.

A useful command for this is strace, which can trace file‑access system calls so you can see what’s needed:

strace -e trace=open,openat,stat,statx,access -o /tmp/strace.log codex

Inspect the log to spot required files and bind‑mount them as appropriate.

Back to Blog

Related posts

Read more »

Defining Safe Hardware Design [pdf]

Article URL: https://people.csail.mit.edu/rachit/files/pubs/safe-hdls.pdf Comments URL: https://news.ycombinator.com/item?id=46873790 Points: 3 Comments: 0...