Skip to content

Repository files navigation

License Docs

claude-sandbox

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/

Why Use 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.

Install

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.

Not a devcontainer user? Prebuilt image

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-container

The 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.

What you get

  • A shadow claude that wraps the real binary in bwrap (--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-ip devices reachable — so a compromised session can't pivot sideways to internal hosts. Fail-closed (needs --device=/dev/net/tun); CLAUDE_SANDBOX_EGRESS_JAIL=0 opts 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).

Documentation

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.

Development

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.

License

See LICENSE.

About

Add a sandboxed claude code to any debian (for now) based devcontainer

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages