Filter environment variables in both sandbox modes

Whitelist mode now clears the parent env and re-adds a small allowlist
(identity, terminal, locale, proxy, non-GUI XDG, vendor prefixes).
Blacklist mode strips cloud credentials, backup passphrases, dangling
socket pointers, and anything matching *_TOKEN, *_SECRET, *_PASSWORD,
*_PASSPHRASE, *_API_KEY, *_PRIVATE_KEY, *_CLIENT_SECRET; vendor prefix
carve-outs keep ANTHROPIC_API_KEY and friends.

Users can override via --setenv KEY=VALUE and --unsetenv KEY (and the
corresponding TOML keys), or opt out of the built-in policy entirely
with --no-env-filter.
This commit is contained in:
2026-04-08 09:22:11 +02:00
parent 12644ae31e
commit 25f0037aab
8 changed files with 638 additions and 5 deletions

View File

@@ -16,6 +16,15 @@ The threat model is prompt injection and accidental damage, not a determined att
**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.
@@ -41,9 +50,11 @@ command = ["claude", "--dangerously-skip-permissions"]
## Escape hatches
When the agent needs access to something the sandbox blocks, use `--rw` or `--ro`:
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
```