Solo Stack Kits Directory
Claude Code workflows & skills for solo consultants and freelancers

← Blog · 2026-11-08

Claude Code Sandbox Not Working? 14 Causes and Fixes

60-second test: ask Claude (don't type it yourself after !, which runs outside the sandbox) to run touch ~/sandbox-probe. Inside the sandbox it fails with Operation not permitted on macOS or Read-only file system on Linux and WSL2. Then ask it to run curl --noproxy '*' https://example.com, which should fail with Could not resolve host. If either one succeeds, the sandbox isn't on: start at cause 1 (and delete ~/sandbox-probe). If both fail as expected, the sandbox works and your problem is something it blocks: go to cause 6. Decline if Claude offers to retry them outside the sandbox.

The Claude Code sandbox is an operating-system boundary around the shell commands Claude runs (Bash, PowerShell and Monitor commands, and the processes they start). It's off by default. You turn it on with /sandbox in a session or "sandbox": {"enabled": true} in a settings file. It runs on macOS (built-in Seatbelt), Linux and WSL2 (bubblewrap and socat). On native Windows, commands always run unsandboxed: use WSL2.

By default a sandboxed command can:

Access Default
Write The working directory, a per-user temp directory and directories you added with --add-dir, /add-dir or permissions.additionalDirectories, minus protected paths
Read Most of the machine, including ~/.ssh and ~/.aws/credentials, unless you deny it
Network Nothing direct. Traffic goes through a local proxy that checks each host against sandbox.network.allowedDomains, which starts empty

Two things the sandbox does not cover, which explains a lot of "it isn't working" reports: Claude's own file and web tools (Read, Edit, Write, WebFetch, WebSearch) follow permission rules instead, and hooks, local MCP servers and your status line command run with your full access.

The sandbox never turns on: 5 causes

  1. Linux or WSL2 is missing bubblewrap or socat. Run /sandbox. If the panel shows only a Dependencies tab, the sandbox can't start, and the tab lists what's missing. Install them (sudo apt-get install bubblewrap socat on Ubuntu/Debian, sudo dnf install bubblewrap socat on Fedora), then restart Claude Code: the dependency check only runs at startup. A Dependencies tab next to the normal tabs means only something optional is missing, such as the seccomp filter (npm install -g @anthropic-ai/sandbox-runtime), and the sandbox can still start. Watch out: by default, if the platform doesn't support the sandbox or the startup check fails, Claude Code silently runs commands without it. Set sandbox.failIfUnavailable to true to make it exit instead.
  2. Ubuntu's AppArmor restriction stops bubblewrap. You see Ubuntu's AppArmor restriction on user namespaces stops bubblewrap here, or commands fail with bwrap: setting up uid map: Permission denied or bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted. Check with sysctl kernel.apparmor_restrict_unprivileged_userns; = 1 means the restriction is on. The narrow fix is an AppArmor profile for /usr/bin/bwrap (the docs give the exact profile to write to /etc/apparmor.d/bwrap, then sudo systemctl reload apparmor). The blunt fix, sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0, lifts it for every program until you reboot. Restart Claude Code and rerun the 60-second test.
  3. You're on WSL1 or native Windows. Sandboxing requires WSL2 means your distribution runs WSL1: check with wsl -l -v in PowerShell and upgrade it. Native Windows has no sandbox at all. Our Claude Code on Windows guide covers the native vs WSL choice.
  4. You're inside an unprivileged container. bubblewrap can't mount a fresh /proc, so commands fail with Can't mount proc on /newroot/proc: Operation not permitted. Set sandbox.enableWeakerNestedSandbox to true so the sandbox reuses the container's /proc. Only do this when the container itself is the isolation boundary you trust, because it exposes process information to sandboxed commands.
  5. /sandbox can't save your choice. Sandbox settings are overridden by a higher-priority configuration and cannot be changed locally means managed settings or a --settings flag already set sandbox.enabled, sandbox.autoAllowBashIfSandboxed or sandbox.allowUnsandboxedCommands; run /status and read the Setting sources line to see which (managed settings need your administrator). Sandbox settings not changed: ... couldn't be updated (EACCES) means /sandbox couldn't write .claude/settings.local.json: start Claude Code in a folder you can write to, fix invalid JSON in that file, or put "sandbox": {"enabled": true} in ~/.claude/settings.json instead. Note that /sandbox saves to the project's local settings, so it's on only in that project until you set it in user settings. Our settings not applying guide explains the precedence.

It's on, but network commands fail: 5 causes

  1. The host isn't allowed. Your allowed domains start empty. In Manual and accept-edits modes you get a prompt the first time a command needs a host: Yes allows it for this session, Yes, and don't ask again saves a WebFetch(domain:...) allow rule to local settings. In dontAsk mode the connection is refused, and in auto mode it's refused unless the command listed the host and the classifier approved. With strictAllowlist or allowManagedDomainsOnly on, there's no prompt in any mode. Pre-allow what your tools need, for example "sandbox": {"network": {"allowedDomains": ["registry.npmjs.org", "github.com"]}}. Tools that use the proxy see a 403 from it when a host isn't allowed.
  2. git push or git pull over SSH fails. On macOS, git over SSH fails inside the sandbox even for an allowed host, because the tunnel can't authenticate to the sandbox proxy. Switch the remote to HTTPS (git remote set-url origin https://... with a personal access token), or take git's network commands out of the sandbox with "excludedCommands": ["git fetch *", "git pull *", "git push *"]. On Linux and WSL2 it works once the host is allowed on port 22 (an entry with no port covers it), your corporate proxy permits port 22, and your key is readable as a file (a denyRead or credentials entry for ~/.ssh hides it).
  3. A database client, plain ssh or another non-HTTP tool can't connect. Tools that ignore the proxy environment variables have no route out, even to an allowed host. You'll see Operation not permitted or Could not resolve host on macOS, Network is unreachable or Temporary failure in name resolution on Linux. UDP, HTTP/3 and ping can't leave either. Run that one command outside the sandbox with a narrow excludedCommands entry, ideally paired with an ask rule so you approve each run, for example "excludedCommands": ["python scripts/load_orders.py *"] plus "permissions": {"ask": ["Bash(python scripts/load_orders.py *)"]}.
  4. A command can't reach your local dev server or a database in Docker. On macOS, set sandbox.network.allowLocalBinding to true (this opens every localhost port to sandboxed commands). On Linux and WSL2 a sandboxed command's localhost is private to it, so allowLocalBinding does nothing there: use excludedCommands for the command that needs the host's server. A dev hostname such as myapp.test that points at 127.0.0.1 is refused with resolved to a loopback address; add both "myapp.test:3000" and "127.0.0.1:3000" to allowedDomains.
  5. gh, gcloud or terraform fail TLS verification on macOS. Go-based CLIs can fail certificate checks under Seatbelt. Add a pattern per tool, such as gh *, to excludedCommands, knowing it then runs with your full access and stored credentials. If you're using a MITM proxy with a custom CA via httpProxyPort, set sandbox.enableWeakerNetworkIsolation to true instead. For corporate proxies and CA bundles in general, see Claude Code proxy and SSL certificate errors.

It's on, but other tools break: 4 causes

  1. docker or jest fails or hangs. docker is incompatible with the sandbox: exclude only what you need, such as "excludedCommands": ["docker compose *"]. jest hangs because watchman doesn't work in the sandbox: run jest --no-watchman. excludedCommands matching is strict: patterns use Bash(...) rule syntax, so end them with *; every command in a chained call must match; a cd, a redirect to a file or a $(...) substitution keeps the whole call sandboxed; and a script that calls docker internally doesn't match.
  2. A write is denied inside your own project. The sandbox protects files Claude Code loads config and code from, even inside writable folders: .claude settings, .claude/skills, agents, commands and hooks, .mcp.json, .git/hooks and .git/config, .vscode, .idea and shell startup files. An allowWrite entry doesn't override that. git merge or git checkout touching one of them fails with unable to unlink old: approve Claude's offer to rerun outside the sandbox, or run it yourself in another terminal. For other tools that need a folder outside the project (~/.kube, a build cache), add it to sandbox.filesystem.allowWrite rather than excluding the tool. /sandbox → Config lists the resolved paths under Denied within allowed.
  3. "Yes, and don't ask again" won't save (Linux and WSL2). A killed session can leave 0-byte read-only placeholder files at .claude settings paths, so later settings writes fail. Run claude doctor, which lists them, and delete each one with rm while no other Claude Code session is open in that project.
  4. Chromium, Podman, the clipboard or open fail. On Linux, Chromium exits with No usable sandbox! and rootless Podman can't create user namespaces: start Chromium or Electron with --no-sandbox, exclude the test or podman command, or set sandbox.allowNestedUserNamespaces to true in user settings (v2.1.305+, and it weakens the boundary). If pbcopy, xclip or wl-copy don't reach the clipboard, ask Claude to print the text and run /copy. On macOS, open, osascript and browser-based sign-ins fail with error -600 because Apple Events are blocked: sandbox.allowAppleEvents (user settings only) allows them but removes code-execution isolation, so excluding open * is the safer choice.

Choosing how much it asks

In auto-allow mode (the default when you enable it in settings) sandboxed commands run without a prompt, but deny rules, content ask rules such as Bash(git push *) and rm on critical paths still go through the normal checks, and Monitor commands still prompt unless an allow rule matches them. Regular permissions mode prompts for every command even when sandboxed; set sandbox.autoAllowBashIfSandboxed to false for it. When a command fails in the sandbox, Claude may retry it unsandboxed with dangerouslyDisableSandbox, which prompts as "Bash command (unsandboxed)" in Manual mode. To forbid that escape hatch, set "allowUnsandboxedCommands": false (shown as Strict sandbox mode in /sandbox). Our free permissions builder writes the allow, ask and deny rules that go next to your sandbox block.


Facts on this page come from Anthropic's Claude Code docs on configuring the sandboxed Bash tool, the settings reference, permissions and network configuration. Behavior differs by Claude Code version; run claude update before digging. This guide isn't affiliated with Anthropic.

Made by Solo Stack Kits. The sandbox limits what commands can touch; hooks can stop the risky ones before they run. Start with our free Claude Code safety hooks, or get the Claude Code Power Config Pack with permission presets and 8 tested safety hooks, $6 with the launch code while it lasts.

Want it set up already? Claude Code Power Config Pack

Fixed it? Skip the next one with a tested Claude Code setup you can drop into any repo.

One install command that backs up your settings first. Checked against the official Claude Code docs. MIT licensed.

Launch price: $6 instead of $12 (code LAUNCH50, first 25 buyers, until Nov 10, 2026).

Get the Config Pack: $6 launch priceOr try 2 of the hooks free

Free on Gumroad: block-dangerous-bash and protect-secrets with a settings snippet. Enter $0; Gumroad asks for an email to deliver the zip.

Prefer to build it yourself? Use the free Claude Code tools, no sign-up.