bwrap-isolated Claude Code for Debian/Ubuntu devcontainers (rootless Podman is
the supported runtime; rootless Docker likely works but is untested with the
default egress jail). A hostile prompt, file, or
tool result cannot reach your host credentials, IDE bridges, or shell
environment. The protection is launch-time: plain claude resolves to a shadow
that wraps the real binary in bwrap, and a global integrity guard fails loud
and closed if it is ever launched unwrapped.
📖 Documentation: https://gilesknap.github.io/claude-sandbox/
Agents are vulnerable to prompt injection embedded in the text they process (web pages, commit messages etc). This can allow a bad actor to take control of your agent. Agents can also make mistakes.
The blast radius for badly behaved agents can be very large when they are running as a user whose credentials are within their reach. All your credentials are often available to an agent running under your account on your workstation.
For this reason Claude code will default to asking for user approval for every tool call it is going to make. But in real use this leads to 'approval fatigue' where users stop checking what the agent is about to do. 'auto-mode' is a partial fix for this as a second agent acts as a classifier for all tool calls and approves those that don't look dangerous. Unfortunately auto-mode has been demonstrated to be defeated by careful prompt injection.
Hence, Anthropic recommend running Claude Code in an isolated environment where it does not have access to your credentials and you carefully control what network devices and filesystem folders it does have access to. claude-sandbox allows you to have that control inside a developer container running locally on your workstation.
This report demonstrates key sandbox isolation properties: https://gist.github.com/gilesknap/582a289874e65b89fc99f09df37cf121.
Inside any Debian/Ubuntu devcontainer (running as root, the typical
rootless-podman pattern):
git clone https://github.com/gilesknap/claude-sandbox.git
cd claude-sandbox
./install
Then run claude as usual — the shadow on $PATH wraps every invocation. The
installer is idempotent; wire bash <clone>/install into your devcontainer's
postCreate.sh to re-establish it on every rebuild.
The getting-started tutorial has the full walkthrough, including the
/user-terminal-config clone location for python-copier-template
devcontainers and how to confirm the install with /verify-sandbox.
A published image (ghcr.io/gilesknap/claude-sandbox) ships the whole sandbox
pre-installed — any Linux host with rootless podman can run sandboxed Claude
Code with no devcontainer and no root access (docker is untested with the
egress jail):
curl -fsSLO https://raw.githubusercontent.com/gilesknap/claude-sandbox/main/container/claude-container
chmod +x claude-container
cd ~/src/my-project && ./claude-containerThe launcher runs unsandboxed on your host — it is ~200 lines of bash; read it
before you run it. See Use the prebuilt container image for
pinning the fetch to a fixed ref, persistence, forge auth, and configuration;
each image records the launcher version it was tested with, and
claude-container tells you when your copy is out of date.
- A shadow
claudethat wraps the real binary inbwrap(--ro-bind / /,--tmpfs $HOME,--clearenv,--cap-drop ALL, PID/IPC/UTS namespaces, TIOCSTI defence) so host credentials and IDE bridges are unreachable. - A per-process egress jail (ADR 0015, on by default) that runs Claude in
its own network namespace and blackholes RFC1918 (internal LANs, lab devices)
while leaving the internet, DNS, and configured
allow-ipdevices reachable — so a compromised session can't pivot sideways to internal hosts. Fail-closed (needs--device=/dev/net/tun);CLAUDE_SANDBOX_EGRESS_JAIL=0opts out. - A global, tamper-resistant integrity guard (highest-precedence managed-settings hooks + a disabled auto-updater) that fails loud and closed if Claude is ever launched outside the shadow.
- Refusal-on-failure: if the host can't run unprivileged user namespaces the installer refuses, rather than install a sandbox that isn't one.
How and why it works: the architecture overview, the threat model, and the network egress jail decision (ADR 0015).
| Tutorial | Get to a working, verified sandbox. |
| How-to guides | Verify, authenticate forges, configure workspace scope, configure the egress jail, promote, upgrade. |
| Reference | Locked-down defences, the egress jail, the verification checks, config keys, deliberate exposures. |
| Explanations | Threat model, architecture, the integrity guard, sandbox internals. |
bash tests/bwrap_argv.sh
bash tests/smoke.sh
bash tests/promote.sh
The same three commands CI runs — bash all the way down, no uv/pytest (see the
contributing guide). The repo's own .claude/ is the canonical
source of the skills and commands the installer ships into target workspaces.
The docs live in docs/ — the one isolated Python toolchain — and publish to
GitHub Pages on every push to main.
See LICENSE.