[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.
3 Comments
Additional data point from macOS, where the mechanism looks different from the Docker/bwrap case above but the user-visible bug is the same: here the sandbox is demonstrably active — filesystem
allowWrite/denyReadenforce, and the network layer otherwise behaves as the documented prompt-mode allowlist — yetstrictAllowlist: truestill does not deny.Environment: Claude Code 2.1.241, macOS (Darwin 25.5.0), interactive session, sandbox enabled via the project's committed
.claude/settings.json:Repro, in a fresh session booted with that committed block (so the sandbox initialized at startup — no mid-session flip):
example.comis not inallowedDomains. Expected: a denial without prompting, per the schema description. Actual: 200 with the real page, and no denial surfaced. (If the sandbox proxy prompted, nothing visible surfaced and the request was allowed; since the setting's contract is deny-without-prompting, a prompt silently resolving to allow would be the same defect.)Reproduced from both settings sources on 2.1.240/241: once with the sandbox block in a repo's
settings.local.json(2026-08-23), once with the block in a committed, trusted.claude/settings.jsonread at session boot (above). In the same sessions the filesystem sandbox layers enforce correctly (writes outsideallowWriteare refused at the sandbox layer), so this is not a sandbox-absent fallback: the network allowlist simply behaves as prompt mode regardless ofstrictAllowlist.Reproduced your exact configuration on 2.1.233 in a Linux container, and the explanation is configuration rather than a broken dispatch path:
sandbox.network.strictAllowlistandsandbox.network.allowedDomainsconfigure the sandbox's network policy, but they don't turn the sandbox on. With only those two keys set (as in your steps), sandboxing is disabled, Bash commands run directly, acurlto a non-allowlisted domain returns 200, and the debug log contains no sandbox activity — exactly what you observed.Enable the sandbox with
"sandbox": { "enabled": true }in~/.claude/settings.json(or via the/sandboxpanel). Re-testing in the same container withenabled: trueplus your network keys, the Bash tool immediately ran commands through the sandbox and the strict allowlist denied access to non-allowlisted hosts — and denied the "run outside the sandbox" fallback — without prompting.Two other notes for your setup:
strictAllowlistrequires Claude Code v2.1.219 or later, so the 2.1.197 half of your testing couldn't have honored it in any configuration.bubblewrapandsocatinstalled). If you want fail-closed rather than warn-and-fall-back when the sandbox can't run, setsandbox.failIfUnavailable: true.Docs: https://code.claude.com/docs/en/sandboxing (see "Enable the sandbox" and the network isolation section).
Your broader point that the setting is silently inert is fair — a warning when
sandbox.network.*keys are set while the sandbox is disabled would make this discoverable, and that's worth a separate feature request. Closing this one since sandboxing andstrictAllowlistwork as documented once enabled.🤖 Generated with Claude Code
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.