[BUG] Sandbox network allowedDomains not enforced on macOS: built-in proxy CONNECTs to non-allowlisted hosts (CLI 2.1.205)

Open 💬 0 comments Opened Jul 13, 2026 by masatoshiadachi-cmd

Environment

  • Claude Code: 2.1.205 (npm install), also reproduced on the macOS desktop app
  • OS: macOS (Darwin 25.5.0, Apple Silicon)
  • No system proxy / no TLS-inspecting middleware on the machine (verified via System keychain certificate search, scutil --proxy, LaunchDaemons, and process list — nothing present)

Sandbox config (project .claude/settings.json)

"sandbox": {
  "enabled": true,
  "autoAllowBashIfSandboxed": false,
  "enableWeakerNetworkIsolation": false,
  "network": {
    "allowedDomains": [
      "github.com", "*.github.com", "*.githubusercontent.com",
      "pypi.org", "files.pythonhosted.org", "registry.npmjs.org",
      "api.openai.com", "chatgpt.com", "auth.openai.com"
    ],
    "allowLocalBinding": true
  },
  "filesystem": { "allowWrite": ["..."] }
}

example.com is not in the allowlist.

Steps to reproduce

  1. Interactive CLI session in the project with the config above.
  2. Ask Claude to run curl -sI https://example.com via the Bash tool (the command is gated by a Bash(curl *) ask rule; approve the prompt).

Expected behavior

Per the sandboxing docs (https://code.claude.com/docs/en/sandboxing): "Network access is controlled through a proxy server running outside the sandbox" and "The built-in proxy enforces the allowlist based on the requested hostname." A plain curl to a non-allowlisted host (genuine hostname, no domain fronting / SNI tricks) should be refused by the proxy.

Actual behavior

The request goes through the sandbox's built-in proxy and reaches example.com:

HTTP/1.1 200 Connection Established

HTTP/2 200
date: Mon, 13 Jul 2026 01:46:54 GMT
content-type: text/html
server: cloudflare
...

Diagnostics confirming it is the built-in sandbox proxy (not an external one)

Environment observed from inside the sandboxed Bash tool (same project, headless claude -p run):

HTTPS_PROXY=http://srt:<redacted-session-token>@localhost:64752
HTTP_PROXY=http://srt:<redacted-session-token>@localhost:64752
ALL_PROXY=http://srt:<redacted-session-token>@localhost:64752
GIT_SSH_COMMAND=ssh ... ProxyCommand='nc -X 5 -x localhost:64752 %h %p'
NO_PROXY=localhost,127.0.0.1,::1,169.254.0.0/16,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16

So curl is definitely going through Claude Code's own localhost proxy, and that proxy is issuing 200 Connection Established for a non-allowlisted host.

What we ruled out

  • Sandbox inactive? No — in the same session, filesystem enforcement works correctly: a permissions.deny Read() path accessed via variable indirection (bypassing string-matching hooks) fails with Operation not permitted (Seatbelt).
  • enableWeakerNetworkIsolation? Explicitly set to false (verified in the session transcript / git state at run time).
  • External MITM proxy / corporate TLS inspection? None installed on this machine (see Environment).
  • Domain fronting? Not applicable — plain curl with the genuine hostname; this is not the documented domain-fronting caveat.

Reproduced on both the desktop app and the CLI, so it does not appear to be client-specific.

Question

Is network.allowedDomains intended to hard-block non-allowlisted hosts in this configuration? If enforcement is currently advisory (or moved to a different mechanism, e.g. the network permission prompt flow), it would be great to have the docs state that explicitly — several hardening setups (including ours) treat the allowlist as an enforced egress control.

View original on GitHub ↗