Toollance

Stop Approving Every Claude Code Command: Set Up the Built-In Sandbox

ai-codingclaude-codeworkflow

If you run Claude Code with default permissions, you’ve clicked “yes” to the same handful of commands a hundred times this week — npm test, git status, ls, another build. A recent XDA Developers piece points at a feature that’s been sitting in Claude Code for a while and mostly goes unused: the built-in Bash sandbox.

What the sandbox actually does

Instead of approving each command one at a time, you define boundaries once — which directories a command can write to, which network domains it can reach — and the operating system enforces them for every Bash command and its child processes. On macOS this uses the built-in Seatbelt framework; on Linux and WSL2 it uses bubblewrap. Nothing to install on macOS. On Linux/WSL2 you need bubblewrap and socat:

sudo apt-get install bubblewrap socat   # Ubuntu/Debian
sudo dnf install bubblewrap socat       # Fedora

Run /sandbox inside a session to open the config panel, or set it globally in ~/.claude/settings.json:

{
  "sandbox": {
    "enabled": true
  }
}

With auto-allow mode turned on, sandboxed Bash commands run without a prompt — the sandbox boundary itself is what replaces the approval click, not a blanket trust of the model. Explicit deny rules, rm -rf /-style destructive paths, and rules scoped to specific commands (like Bash(git push *)) still force a prompt even inside the sandbox.

Why this is a bigger deal than it looks

This matters for a reason beyond convenience. OpenAI confirmed this week that GPT-5.6 can attempt to override the $HOME environment variable to create a temp directory — and sometimes deletes the real $HOME instead. OpenAI’s own note on the incident is specific about when it happens: “when full access mode is enabled, and Codex is run without sandboxing protections, including without auto review being enabled.” In other words, the failure mode isn’t hypothetical, and the fix isn’t a smarter model — it’s exactly the kind of OS-level write boundary Claude Code’s sandbox already enforces by default (writes restricted to the working directory and session temp dir, nothing outside it without an explicit allowWrite rule).

That distinction matters: permission rules in any agent are evaluated by matching command strings before the command runs. A sandbox boundary is enforced by the kernel on the running process, so it holds even if the model’s plan quietly does more than the command name suggests.

A config recipe for a typical repo

Most real repos need a few tools to write or read outside the working directory. Grant those explicitly instead of disabling the sandbox for them:

{
  "sandbox": {
    "enabled": true,
    "filesystem": {
      "allowWrite": ["~/.kube", "/tmp/build"],
      "denyRead": ["~/.ssh", "~/.aws/credentials"]
    },
    "credentials": {
      "envVars": [
        { "name": "GITHUB_TOKEN", "mode": "deny" },
        { "name": "NPM_TOKEN", "mode": "deny" }
      ]
    }
  }
}

allowWrite covers tools like kubectl or terraform that need to write outside your project directory — these restrictions are OS-enforced, so they apply to every subprocess a command spawns, not just Claude’s own file-edit tools. Run any config edits through a JSON Validator before saving settings.json — a stray trailing comma there silently breaks the whole sandbox config on the next session start.

A few gotchas to know before you hit them mid-task:

The takeaway

The sandbox doesn’t make Claude Code smarter about what to run — it makes the blast radius smaller when something goes wrong, which is the actual problem the Codex $HOME incident illustrates. If you’re currently approving every npm test and ls by hand, that’s fifteen minutes of settings.json work you get back on every session afterward.