[BUG] `sandbox.network.strictAllowlist` has no effect — Bash tool dispatcher never invokes bwrap, on any tested version
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
With sandbox.network.strictAllowlist: true set in user settings, Bash tool commands are documented to run through an isolated (bwrap) sandbox that hard-denies network access to non-allowlisted domains, without prompting. In our environment (Claude Code running inside a Docker container), this setting has no observable effect: Bash commands execute directly and can reach arbitrary non-allowlisted domains. Debug logging shows the Bash tool dispatcher never attempts to invoke bwrap at all — this isn't a case of sandbox setup failing and falling back open, it's simply absent from the dispatch path.
What Should Happen?
A curl (or any Bash command) targeting a domain not in allowedDomains should be blocked without prompting, per the settings description ("deny non-allowlisted hosts for sandboxed commands without prompting").
Error Messages/Logs
[INFO] [Stall] tool_dispatch_start tool=Bash toolUseId=... permissionDecisionMs=15
[DEBUG] Creating shell snapshot for bash (/bin/bash)
[DEBUG] Looking for shell config file: /home/node/.bashrc
[DEBUG] Snapshots directory: /home/node/.claude/shell-snapshots
[DEBUG] Creating snapshot at: ...
[DEBUG] Execution timeout: 10000ms
[DEBUG] Spawn-env probe captured 26 keys
[DEBUG] Shell snapshot created successfully (4789 bytes)
[DEBUG] No session environment scripts found
[DEBUG] Spawning shell without login (-l flag skipped)
[INFO] [Stall] tool_dispatch_end tool=Bash toolUseId=... outcome=ok durationMs=46
Zero log lines anywhere in the full startup+dispatch trace mention bwrap, sandbox, namespace, seccomp, apparmor, or container detection — despite the log being verbose about comparatively minor steps (CA cert loading, shell snapshot creation, permission-decision timing).
Steps to Reproduce
- Set sandbox.network.strictAllowlist: true and sandbox.network.allowedDomains: ["github.com", "registry.npmjs.org"] in ~/.claude/settings.json (user-level).
- Run Claude Code inside a Docker container (non-root user), with bwrap available and working standalone in the container (confirmed via
bwrap --unshare-net --ro-bind / / -- curl https://www.ebi.ac.uk, which correctly fails to resolve — bwrap itself works fine). - From the Bash tool, run: curl https://www.ebi.ac.uk/ (a domain not in allowedDomains).
- Observe HTTP 200 — the request succeeds and reaches a non-allowlisted domain, instead of being blocked.
- Optionally confirm via
--debug(see logs below) that the Bash tool dispatch sequence never invokes bwrap, and via /proc/<pid>/status PPid chain that the spawned shell is a direct child of the claude process, with no bwrap process in the ancestry.
Claude Model
Not sure / Multiple models
Is this a regression?
No, this never worked
Last Working Version
none
Claude Code Version
2.1.197 and 2.1.233 (identical behavior on both).
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Other
Additional Information
Ruled out bwrap itself as the blocker: after adding --cap-add SYS_ADMIN --security-opt seccomp=unconfined --security-opt apparmor=unconfined to our docker run invocation (required only because Docker's default seccomp/AppArmor profiles block clone(CLONE_NEWUSER)/mount, which bwrap --unshare-net needs), manually invoking bwrap --unshare-net --ro-bind / / -- curl https://www.ebi.ac.uk/ correctly fails with "Could not resolve host" — bwrap itself is fully capable of network isolation here. The gap is specifically that Claude Code's Bash tool dispatcher doesn't invoke it.
Also confirmed session permissionMode was "default" (not bypassPermissions) via the session's own transcript, ruling out a permission-mode explanation.
Hypotheses (unconfirmed):
- Sandboxing may be intentionally disabled when Claude Code detects it's already running inside a container — reasonable instinct, but undocumented/unconfigurable, and container-nesting is exactly the scenario strictAllowlist is most useful for (e.g. an ingest workflow that curls untrusted external content).
- A startup-time capability/support detection step may silently decide "sandboxing unsupported here" with no corresponding log line even at --debug verbosity.
Impact: strictAllowlist is our primary defense against prompt-injection → exfiltration (our workflow feeds raw externally-sourced documents into the agent via curl). Right now that protection is a complete no-op in our environment, silently, with no warning surfaced to the user or the agent.
Ask: confirmation of whether Bash-tool sandboxing is expected to work when Claude Code itself runs inside Docker, and if not, whether that's documented; if it's a bug, a fix or at minimum a visible warning instead of silent fail-open; if deliberate, guidance on achieving equivalent containment when nested in Docker.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗