Files
agent-sandbox/README.md

71 lines
4.4 KiB
Markdown

# agent-sandbox
Sandbox agentic coding assistants with [bubblewrap](https://github.com/containers/bubblewrap). Limits what an AI agent can see and modify on the host, reducing the blast radius of prompt injection and accidental damage.
## Modes
### Whitelist
Tight sandbox for normal agent coding tasks. Only explicitly listed paths are visible — system binaries, libraries, a subset of `/etc`, `/sys` (all read-only), synthetic `/dev`, private `/proc`, `/tmp`, `/run`, and the working directory (read-write). Everything else is invisible.
### Blacklist
Looser sandbox for system-level debugging with agent assistance. The host filesystem is mounted read-only, with targeted overlays hiding sensitive paths (credentials, history, secrets, sockets, input devices). `/run` and `${XDG_RUNTIME_DIR}` are replaced with tmpfs mounts that only expose the paths needed for system tooling (`systemctl`, `resolvectl`, `journalctl`, etc.).
The threat model is prompt injection and accidental damage, not a determined attacker with user-level access.
**Not protected in blacklist mode:** arbitrary readable files outside the sensitive paths list, and D-Bus method calls (access control is daemon-side).
## Environment filtering
Both modes clamp the environment the child sees so prompt-injected agents can't `printenv` their way to secrets.
- **Whitelist** clears the parent env and re-adds a small allowlist: identity/shell vars (`HOME`, `PATH`, …), terminal/locale, proxy, non-GUI XDG base dirs, and agent vendor prefixes (`ANTHROPIC_*`, `CLAUDE_*`, `OPENAI_*`, `CODEX_*`, `GEMINI_*`, `OTEL_*`).
- **Blacklist** keeps the parent env but unsets credentials and dangling pointers: cloud creds (`AWS_*`, `GOOGLE_APPLICATION_CREDENTIALS`, …), backup tool passphrases, sockets stripped by path overlays (`SSH_AUTH_SOCK`, `DISPLAY`, `GNUPGHOME`, …), and anything matching `*_TOKEN`, `*_SECRET`, `*_PASSWORD`, `*_PASSPHRASE`, `*_API_KEY`, `*_PRIVATE_KEY`, `*_CLIENT_SECRET`. Vendor-prefix vars (`ANTHROPIC_API_KEY` etc.) are carved out so they survive.
Disable the built-in policy entirely with `--no-env-filter` (or `env-filter = false` in the config file) to pass the parent env through unchanged. User `--setenv`/`--unsetenv` escape hatches still apply.
## Seccomp
Both modes apply a seccomp-BPF syscall allowlist derived from Podman's default profile. Dangerous syscalls (`mount`, `unshare`, `ptrace`, `bpf`, `perf_event_open`, `io_uring_*`, `keyctl`, `kexec_*`, …) return `ENOSYS`. Disable with `--no-seccomp` or `seccomp = false` in the config file.
## Configuration file
Settings can be stored in a TOML config file at `$XDG_CONFIG_HOME/agent-sandbox/config.toml` (or pass `--config <path>`). Use `--no-config` to skip loading it. The config file accepts the same options as the corresponding CLI flags.
Top-level keys set defaults; `[profile.<name>]` sections define named presets selectable with `--profile <name>`. CLI flags always take highest precedence, followed by the active profile, then top-level defaults.
```toml
# Global defaults
whitelist = true
unshare-net = true
ro = ["~/.aws"]
# Named profile
[profile.docker]
blacklist = true
rw = ["/var/run/docker.sock"]
command = ["claude", "--dangerously-skip-permissions"]
```
## Escape hatches
When the agent needs access to something the sandbox blocks, use `--rw` or `--ro` for paths and `--setenv`/`--unsetenv` for env vars. User overrides always win over the built-in policies.
```bash
agent-sandbox --rw /var/run/docker.sock -- claude --dangerously-skip-permissions
agent-sandbox --ro ~/.aws -- claude --dangerously-skip-permissions
agent-sandbox --setenv DATABASE_URL=postgres://localhost/dev -- claude
agent-sandbox --unsetenv HTTP_PROXY -- claude
```
## Ubuntu 23.10+: AppArmor unprivileged userns restrictions
Ubuntu 23.10 and later ship with `kernel.apparmor_restrict_unprivileged_userns=1`, which blocks `bwrap` from creating user namespaces and causes failures like `bwrap: setting up uid map: Permission denied`. Ubuntu does not enable a profile for `bwrap` by default, but the `apparmor-profiles` package ships an opt-in `bwrap-userns-restrict` profile that grants the necessary access while still preventing `bwrap` from being used to bypass the userns restriction generally:
```bash
sudo apt install apparmor-profiles
sudo ln -s /usr/share/apparmor/extra-profiles/bwrap-userns-restrict /etc/apparmor.d/
sudo apparmor_parser -r /etc/apparmor.d/bwrap-userns-restrict
```