Home / Session 8
session-8.md — ~/hacking-with-ai
8

Sandboxing & Security

Isolate Claude Code with OS sandboxes, containers, and microVMs

60 min Sandbox + Docker Sandboxes + Defense-in-Depth Loading...
Session 8 of 8

// Overview

Running Claude Code without isolation is risky. Four CVEs have been published (including CVSS 8.7 RCE), sandbox escapes have been demonstrated, and real-world incidents have resulted in deleted home directories and wiped production databases. This session covers every major sandboxing approach — from the built-in native sandbox to Docker microVMs to Trail of Bits devcontainers — and teaches you to layer them into a defense-in-depth strategy. No single method is sufficient; the community consensus is to combine multiple isolation boundaries.

Learning Objectives

// Theory

Why Sandboxing Matters

10 min

Claude Code has full access to your filesystem and can execute arbitrary shell commands. Without isolation, a single bad command can delete your home directory, exfiltrate API keys, or wipe a production database. Four CVEs have been published — all sharing the same pattern: malicious repository configuration files trigger code execution before the user sees any trust prompt. Real incidents include a user losing their entire home directory (rm -rf ~/), a production database with 2 million rows wiped via terraform destroy, and an autonomous bot (HackerBot-Claw) achieving RCE in 5 of 7 targeted GitHub Actions workflows at Microsoft, DataDog, and CNCF projects.

Key Concepts

  • Four CVEs published: Yarn plugin RCE (CVSS 7.7), project config RCE (CVSS 8.7), API key exfiltration (CVSS 5.3) — all pre-trust attacks via malicious repo files
  • Real incident: user asked Claude to clean up packages, it ran rm -rf tests/ patches/ plan/ ~/ — trailing ~/ destroyed the entire home directory (1,500+ upvotes on Reddit)
  • Real incident: Claude executed terraform destroy, wiping 2.5 years of data — 2 million rows from a learning platform
  • HackerBot-Claw campaign (Feb-Mar 2026): autonomous bot targeted GitHub Actions at Microsoft, DataDog, CNCF — achieved RCE in 5 of 7 targets over 7 days
  • PromptArmor .docx attack: hidden text inside a Word doc manipulated Claude into uploading sensitive files to an attacker's account via the allowlisted API
  • Survey data: 32% of developers using --dangerously-skip-permissions encountered unintended file modification; 9% reported actual data loss
  • All filesystem incidents involved --dangerously-skip-permissions — never run this on a host machine
diagram
Real-World Incidents Timeline
═════════════════════════════
Dec 2025    Home directory deletion (rm -rf ~/)
            └─ User lost desktop files, Keychain, app data

Jan 2026    PromptArmor .docx prompt injection
            └─ Hidden text exfiltrated files via allowlisted API

Jan 2026    Cowork data deletion (11 GB lost)
            └─ Claude ran rm -rf despite explicit "retain data" instructions

Feb 2026    HackerBot-Claw GitHub Actions campaign
            └─ RCE in 5/7 targets (Microsoft, DataDog, CNCF)
            └─ Stole GitHub token from awesome-go (140k stars)

Mar 2026    Production DB wipe (terraform destroy)
            └─ 2 million rows, 2.5 years of data

Common factor: --dangerously-skip-permissions on host machine

Native Sandbox (Built-in)

10 min

Claude Code ships with built-in sandboxing using OS-level primitives: macOS Seatbelt (sandbox-exec) on macOS and bubblewrap (bwrap) on Linux/WSL2. The sandbox restricts filesystem writes to the current working directory and routes all network traffic through a proxy that enforces domain allowlists. It reduces permission prompts by 84% in Anthropic's internal usage. However, it has critical limitations: it's not enabled by default, the escape hatch (allowUnsandboxedCommands) is on by default and the request to change this was closed as 'NOT PLANNED', and it only applies to the Bash tool — Claude's built-in Read, Write, Edit, Glob tools bypass the sandbox entirely.

Key Concepts

  • Enable via /sandbox command or sandbox.enabled: true in settings.json — not enabled by default
  • Filesystem: write access restricted to CWD; read access to entire system minus explicitly denied paths
  • Network: all outbound traffic routes through a proxy — unknown domains trigger a user prompt
  • macOS uses Seatbelt (sandbox-exec) — no deps required, but Apple marks it as deprecated
  • Linux uses bubblewrap + socat — requires apt install bubblewrap socat
  • CRITICAL: Only applies to Bash tool — Read, Write, Edit, Glob bypass the sandbox entirely (GitHub #15789)
  • CRITICAL: allowUnsandboxedCommands defaults to true — Claude can retry failed commands outside the sandbox. Set to false.
  • Default read access is unrestricted — agent can read ~/.ssh, ~/.aws unless explicitly denied via denyRead
  • Path-based denylist uses string matching, not realpath — bypassed with /proc/self/root symlinks (known since ~2009)
  • Known bugs: /sandbox command sometimes doesn't enable sandbox (#31993), excludedCommands broken (#17821)
diagram
// Recommended sandbox settings (settings.json):

{
  "sandbox": {
    "enabled": true,
    "autoAllowBashIfSandboxed": true,
    "allowUnsandboxedCommands": false,     // ← CRITICAL: default is true!
    "excludedCommands": ["docker"],
    "filesystem": {
      "allowWrite": ["/tmp/build"],
      "denyWrite": ["/etc", "/usr/local/bin"],
      "denyRead": [
        "~/.ssh", "~/.aws/credentials",
        "~/.npmrc", "~/.gnupg",
        "~/.config/gh", "~/.git-credentials"
      ]
    },
    "network": {
      "allowedDomains": ["github.com", "*.npmjs.org"]
    }
  }
}

Docker Sandboxes (MicroVM Isolation)

10 min

Docker's official Sandboxes product runs Claude Code inside dedicated microVMs — not regular containers. Each sandbox gets its own Linux kernel, private Docker daemon, and only explicitly mounted project directories. This is the strongest turnkey isolation available. On macOS it uses the Apple Virtualization Framework, on Windows it uses Hyper-V microVMs. File sync is bidirectional via Mutagen (not volume mounts). Because the microVM is the security boundary, --dangerously-skip-permissions is safe inside it. The key difference vs regular containers: containers share the host kernel (kernel exploits can escape), while microVMs have a hypervisor boundary.

Key Concepts

  • MicroVM = separate kernel — even if Claude escapes its own sandbox, it's trapped in an isolated VM
  • Private Docker daemon per sandbox — Claude can build/run containers without host access
  • File sync via Mutagen — bidirectional, not volume mounts. Host edits appear in sandbox and vice versa
  • --dangerously-skip-permissions is safe inside the microVM boundary
  • Network proxy with allow/deny/CIDR policies: docker sandbox network proxy my-sandbox --policy deny --allow-host api.anthropic.com
  • Custom templates: FROM docker/sandbox-templates:claude-code, add your tools (JDK, Maven, etc.)
  • Requires Docker Desktop 4.50+ — Linux support is experimental (falls back to container isolation, not microVM)
  • Included in Docker Desktop free tier (Personal plan: <250 employees AND <$10M revenue)
  • Known limitation: user-level Claude config (~/.claude) not inherited inside sandbox
  • First run downloads ~1 GB microVM image
diagram
# Docker Sandboxes CLI
═══════════════════════

# Run Claude Code in a microVM sandbox
docker sandbox run claude ~/my-project

# Named sandbox (reuses existing)
docker sandbox run --name my-sandbox claude ~/my-project

# Multiple workspaces, with read-only
docker sandbox run claude ~/project ~/shared-libs:ro

# Network: deny-all, then allow specific hosts
docker sandbox network proxy my-sandbox --policy deny \
  --allow-host api.anthropic.com \
  --allow-host github.com

# Custom template with your toolchain
docker build -t my-template:v1 .
docker sandbox run --template my-template:v1 claude ~/project

# Management
docker sandbox ls
docker sandbox exec -it my-sandbox bash
docker sandbox rm my-sandbox

┌──────────────────────────────────────────────────────┐
│        Regular Container vs Docker Sandbox            │
├───────────────┬──────────────┬────────────────────────┤
│ Aspect        │ Container    │ Docker Sandbox         │
├───────────────┼──────────────┼────────────────────────┤
│ Isolation     │ Shared kernel│ Separate kernel (VM)   │
│ Escape risk   │ Kernel exploit│ Hypervisor boundary   │
│ Docker-in-Docker│ Host socket│ Private daemon         │
│ Network       │ Basic Docker │ HTTP/S filtering proxy │
│ Files         │ Volume mount │ Bidirectional sync     │
└───────────────┴──────────────┴────────────────────────┘

Trail of Bits Devcontainer & Other Tools

5 min

The Trail of Bits devcontainer is purpose-built by a well-known security firm for running Claude Code with bypassPermissions safely. It includes Ubuntu 24.04, comprehensive deny rules, NPM supply chain mitigations (blocks packages less than 24 hours old), PreToolUse hooks blocking rm -rf and git push to main, and persistent volumes for config. Network is open by default but can be hardened with iptables. Other notable tools include: cco (Claude Condom) for quick zero-config macOS sandboxing, Cloudflare Sandbox SDK for CI/CD pipelines, Anthropic's open-source sandbox-runtime for isolating MCP servers, community Docker projects like FoamoftheSea's 4-layer defense-in-depth with 28 automated security tests, and Spritz for Kubernetes-native enterprise deployments.

Key Concepts

  • Trail of Bits devcontainer (549 stars): Ubuntu 24.04, comprehensive deny rules, NPM supply chain mitigations
  • Trail of Bits hardening: NPM_CONFIG_MINIMUM_RELEASE_AGE=1440 blocks packages <24h old, enableAllProjectMcpServers: false
  • Trail of Bits hooks: block rm -rf (suggest trash), block git push to main/master
  • Trail of Bits companion config (1,633 stars): /review-pr, /fix-issue, /merge-dependabot slash commands
  • cco (Claude Condom): simplest setup — replace claude with cco, auto-detects best sandbox backend
  • Cloudflare Sandbox SDK (928 stars): cloud containers, API-driven, best for CI/CD ($5/mo+ Workers plan)
  • Anthropic sandbox-runtime (3,452 stars): open-source, sandboxes any process including MCP servers
  • FoamoftheSea Docker project: 4-layer defense-in-depth with iptables default-deny and 28 automated security tests
  • Spritz (Kubernetes-native): CRD-based agent instances, enterprise multi-agent at scale
  • ClaudeCage: single binary, zero deps, Linux namespaces — drop-in claude replacement
diagram
Tool Landscape (March 2026)
══════════════════════════

┌─────────────────────────────────────────────────────────────────┐
│ Isolation Level    │ Tools                    │ Best For         │
├────────────────────┼──────────────────────────┼──────────────────┤
│ OS-level           │ Native Sandbox           │ Day-to-day dev   │
│ (Seatbelt/bwrap)   │ cco, ClaudeCage         │                  │
│                    │ Sandbox Runtime           │ MCP servers      │
├────────────────────┼──────────────────────────┼──────────────────┤
│ Container          │ Trail of Bits devcontainer│ Security audits  │
│ (shared kernel)    │ Community Docker projects │ Untrusted code   │
├────────────────────┼──────────────────────────┼──────────────────┤
│ MicroVM            │ Docker Sandboxes          │ Autonomous ops   │
│ (separate kernel)  │ moru (Firecracker)       │ Unattended       │
├────────────────────┼──────────────────────────┼──────────────────┤
│ Cloud              │ Cloudflare Sandbox SDK    │ CI/CD pipelines  │
├────────────────────┼──────────────────────────┼──────────────────┤
│ Kubernetes         │ Spritz                    │ Enterprise       │
│                    │ alibaba/OpenSandbox       │ Multi-agent      │
└────────────────────┴──────────────────────────┴──────────────────┘

// Setup

Verify your sandbox environment and install bubblewrap (Linux) or check Seatbelt (macOS).

bash
# Check if sandbox is available
claude /sandbox
# Linux: install bubblewrap + socat
sudo apt install bubblewrap socat
# macOS: sandbox-exec is built-in (no install needed)
# Docker Sandboxes: requires Docker Desktop 4.50+
docker --version
Verify: The /sandbox command shows sandbox status. On Linux, which bwrap returns a path. On macOS, which sandbox-exec returns /usr/bin/sandbox-exec. For Docker Sandboxes, docker sandbox ls runs without error.

// Challenge

Configure Defense-in-Depth

25m +10m bonus

Layer four security boundaries: permission deny rules, PreToolUse hooks, native OS sandbox, and container isolation. Test each layer by verifying that Claude cannot read ~/.ssh, cannot run rm -rf, and cannot access blocked network domains.

✓ Success Criteria

  • Permission deny rules block Read(~/.ssh/**) and Bash(rm -rf *)
  • Native sandbox enabled with allowUnsandboxedCommands: false
  • denyRead configured for ~/.ssh, ~/.aws, ~/.gnupg, ~/.npmrc
  • Network allowlist configured (only necessary domains)
  • Claude cannot read sensitive files or run destructive commands
  • Bonus: Docker Sandboxes running with network deny policy
⚠ Hints (click to reveal)
  • Start with the native sandbox: enable it and set allowUnsandboxedCommands to false
  • Add denyRead rules for sensitive paths — by default nothing is denied
  • Permission deny rules only block built-in tools — the sandbox enforces at the OS level for Bash
  • Test your setup: ask Claude to cat ~/.ssh/id_rsa and verify it's blocked
  • For Docker Sandboxes: docker sandbox run claude ~/project, then docker sandbox network proxy --policy deny --allow-host api.anthropic.com
  • Remember: /proc/self/root can bypass path-based denylists — container isolation is the real boundary

Code Playground

Interactive

Try These Prompts

Enable native sandbox
Help me configure the native sandbox with strict settings: enabled, no unsandboxed commands, deny reads to all sensitive paths (~/.ssh, ~/.aws, ~/.gnupg, ~/.npmrc, ~/.config/gh, ~/.git-credentials), and a minimal network allowlist.
Use /sandbox or edit ~/.claude/settings.json directly
Expected: Claude creates a comprehensive sandbox configuration in settings.json with all sensitive paths in denyRead and allowUnsandboxedCommands: false
Test sandbox boundaries
Try to read my SSH keys at ~/.ssh/id_rsa. Then try to access the same path via /proc/self/root/home/$USER/.ssh/id_rsa. Report what happens with each attempt.
This tests the string-matching limitation of the denylist — /proc/self/root bypasses it
Expected: Direct path is blocked by denyRead. The /proc/self/root path may bypass the string-matching denylist — demonstrating why container isolation matters
Permission deny rules
Add permission deny rules to block: rm -rf, sudo, wget piped to bash, git push --force, git reset --hard, and reading of SSH keys, AWS credentials, and npm tokens.
These go in the permissions.deny array in settings.json
Expected: Claude adds comprehensive deny rules covering destructive commands and credential access
Docker Sandbox setup
Set up a Docker Sandbox with a deny-all network policy that only allows api.anthropic.com, github.com, and registry.npmjs.org. Create a custom template that includes JDK 21 and Maven.
Use docker sandbox run, then docker sandbox network proxy with --policy deny and --allow-host flags
Expected: Claude creates a Dockerfile extending docker/sandbox-templates:claude-code, builds it, runs a named sandbox, and configures the network proxy
Audit current security
Audit my current Claude Code security posture. Check: is sandbox enabled? Is allowUnsandboxedCommands false? Are there denyRead rules? Are there permission deny rules? Are there PreToolUse hooks? What MCP servers are configured and are any auto-approved?
Check ~/.claude/settings.json, project .claude/settings.json, and .mcp.json
Expected: Claude reads all settings files and produces a security audit with specific recommendations for each gap found

Code Examples

Defense-in-Depth Settings
// ~/.claude/settings.json — Recommended security baseline
{
  "permissions": {
    "deny": [
      "Bash(rm -rf *)", "Bash(sudo *)", "Bash(wget *|bash*)",
      "Bash(curl *|bash*)", "Bash(git push --force*)",
      "Bash(git reset --hard*)", "Bash(chmod 777 *)",
      "Read(~/.ssh/**)", "Read(~/.aws/**)", "Read(~/.npmrc)",
      "Read(~/.config/gh/**)", "Read(~/.git-credentials)",
      "Edit(~/.bashrc)", "Edit(~/.zshrc)", "Edit(~/.profile)"
    ]
  },
  "sandbox": {
    "enabled": true,
    "autoAllowBashIfSandboxed": true,
    "allowUnsandboxedCommands": false,
    "excludedCommands": ["docker"],
    "filesystem": {
      "allowWrite": ["/tmp/build"],
      "denyWrite": ["/etc", "/usr/local/bin"],
      "denyRead": [
        "~/.ssh", "~/.aws/credentials", "~/.npmrc",
        "~/.gnupg", "~/.config/gh", "~/.git-credentials",
        "~/.kube/config", "~/.docker/config.json"
      ]
    },
    "network": {
      "allowedDomains": [
        "github.com", "*.npmjs.org", "api.anthropic.com",
        "registry.yarnpkg.com"
      ]
    }
  },
  "enableAllProjectMcpServers": false
}
Docker Sandboxes Workflow
# ── Docker Sandboxes: strongest turnkey isolation ──

# 1. Run Claude Code in a microVM sandbox
docker sandbox run --name secure-dev claude ~/my-project

# 2. Lock down network (deny-all + allowlist)
docker sandbox network proxy secure-dev --policy deny \
  --allow-host api.anthropic.com \
  --allow-host github.com \
  --allow-host registry.npmjs.org

# 3. Custom template with your toolchain
cat > Dockerfile <<'EOF'
FROM docker/sandbox-templates:claude-code
USER root
RUN apt-get update && apt-get install -y \
    build-essential openjdk-21-jdk maven \
    ripgrep fd-find
USER agent
EOF
docker build -t my-sandbox-template:v1 .
docker sandbox run --template my-sandbox-template:v1 claude ~/project

# 4. Multiple workspaces (read-only for shared libs)
docker sandbox run claude ~/project ~/shared-libs:ro ~/docs:readonly

# 5. Pass environment variables
docker sandbox run -e NODE_ENV=development \
  -e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY claude ~/project

# 6. Management commands
docker sandbox ls                          # List sandboxes
docker sandbox inspect secure-dev          # View details
docker sandbox exec -it secure-dev bash    # Shell in
docker sandbox network log secure-dev      # View network logs
docker sandbox rm secure-dev               # Remove
Trail of Bits Devcontainer
# ── Trail of Bits: security-auditor's devcontainer ──

# Install
git clone https://github.com/trailofbits/claude-code-devcontainer \
  ~/.claude-devcontainer
~/.claude-devcontainer/install.sh self-install

# Start a container for your project
devc .              # Install template + start container
devc up             # Start the devcontainer
devc shell          # Open zsh shell inside
devc exec CMD       # Run a command inside

# What's included out of the box:
# - Ubuntu 24.04, Node.js 22, Python 3.13 + uv
# - ripgrep, fd, tmux (200k scrollback), fzf, ast-grep
# - NPM_CONFIG_IGNORE_SCRIPTS=true (blocks postinstall)
# - NPM_CONFIG_MINIMUM_RELEASE_AGE=1440 (blocks <24h packages)
# - enableAllProjectMcpServers: false
# - Deny rules: SSH keys, cloud creds, package tokens, wallets
# - PreToolUse hooks: block rm -rf, block git push to main

# Manual network hardening (inside container):
sudo iptables -A OUTPUT -d api.anthropic.com -j ACCEPT
sudo iptables -A OUTPUT -d github.com -j ACCEPT
sudo iptables -A OUTPUT -d registry.npmjs.org -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT
sudo iptables -A OUTPUT -j DROP

# Companion config (opinionated defaults):
# github.com/trailofbits/claude-code-config (1,633 stars)
# Adds /review-pr, /fix-issue, /merge-dependabot commands
Comparison Matrix
Sandboxing Methods Comparison
═════════════════════════════

Method              │ Isolation    │ Setup  │ Overhead │ Network  │ Best For
────────────────────┼──────────────┼────────┼──────────┼──────────┼─────────────────
Native Sandbox      │ OS-level     │ 1 min  │ ~0       │ Domain   │ Day-to-day dev
                    │ (Seatbelt/   │        │          │ allowlist│
                    │  bwrap)      │        │          │          │
────────────────────┼──────────────┼────────┼──────────┼──────────┼─────────────────
Docker Sandboxes    │ MicroVM      │ 5 min  │ Moderate │ Allow/   │ Autonomous ops
                    │ (separate    │        │          │ deny     │ Unattended
                    │  kernel)     │        │          │ proxy    │
────────────────────┼──────────────┼────────┼──────────┼──────────┼─────────────────
Trail of Bits       │ Container    │ 15 min │ Low      │ Optional │ Security audits
devcontainer        │ (Docker)     │        │          │ iptables │ Untrusted code
────────────────────┼──────────────┼────────┼──────────┼──────────┼─────────────────
cco                 │ OS-level or  │ 1 min  │ ~0       │ None     │ Quick macOS
                    │ Docker       │        │          │          │ sandboxing
────────────────────┼──────────────┼────────┼──────────┼──────────┼─────────────────
Cloudflare SDK      │ Cloud        │ 30 min │ Cold     │ Cloud-   │ CI/CD pipelines
                    │ container    │        │ start ms │ managed  │
────────────────────┼──────────────┼────────┼──────────┼──────────┼─────────────────
Sandbox Runtime     │ OS-level     │ 2 min  │ ~0       │ Domain   │ MCP servers
                    │ (standalone) │        │          │ allowlist│ Auxiliary tools
────────────────────┼──────────────┼────────┼──────────┼──────────┼─────────────────
Spritz              │ Kubernetes   │ Hours  │ Low      │ K8s      │ Enterprise
                    │ pod          │        │          │ Network  │ multi-agent
                    │              │        │          │ Policy   │

Recommendations by Use Case:
────────────────────────────
Day-to-day local dev:
  Native sandbox + Trail of Bits deny rules + cco (optional)

Untrusted repos:
  Trail of Bits devcontainer + iptables + native sandbox inside

Autonomous / unattended:
  Docker Sandboxes microVM + --dangerously-skip-permissions + network deny

CI/CD pipelines:
  Cloudflare Sandbox SDK  or  Docker Sandboxes in CI runner

Maximum security ("paranoid mode"):
  Docker Sandboxes microVM
  + Native sandbox inside VM (allowUnsandboxedCommands: false)
  + Aggressive denyRead rules
  + Network proxy deny-all + minimal allowlist
  + PreToolUse hooks (rm -rf blocker, prompt injection scanner)

// Key Takeaways

// Resources

Claude Code Sandboxing Docs Anthropic Engineering: Claude Code Sandboxing Docker Sandboxes: Claude Code Docker Sandboxes: Network Policies Trail of Bits Devcontainer Trail of Bits Config Anthropic Sandbox Runtime Cloudflare Sandbox SDK Anthropic Settings Examples Ona: Sandbox Escape Research