Bash sandbox blocks Go binaries' DNS resolution for hosts already on `allowedHosts`
Summary
The Claude Code Bash sandbox returns no such host to Go's net.LookupHost for hostnames that are explicitly on its allowedHosts list. Both Go's pure-Go resolver and the cgo (libc) resolver fail identically. The same hostnames resolve cleanly via nslookup, dig, and curl from the same Bash sandbox in the same shell.
Practical impact: third-party Go-based CLIs cannot run inside the sandbox even when the hosts they talk to are allowlisted. I hit this with Google's Antigravity CLI (agy), but it applies to any Go binary that hits a network. The CLI exits 0 with empty stdout, so the failure is invisible unless you happen to inspect its log files.
Reproduction
Inside a Claude Code Bash session on macOS (darwin/arm64, Claude Code v2.x):
# Hosts that ARE on the sandbox allowlist (confirmed via curl/nslookup):
# cloudcode-pa.googleapis.com
# play.googleapis.com
# storage.googleapis.com
# curl reaches them (404 = reachable, just no path):
$ curl -s -o /dev/null -w "%{http_code}" https://cloudcode-pa.googleapis.com/
404
$ curl -s -o /dev/null -w "%{http_code}" https://play.googleapis.com/
404
# nslookup resolves them:
$ nslookup cloudcode-pa.googleapis.com | grep Address | tail -1
Address: 172.217.29.42
# But a minimal Go program in the same shell fails for ALL of them,
# including the allowlisted ones, with both the pure-Go and cgo resolvers:
$ cat > "$TMPDIR/dnstest.go" <<'GO'
package main
import ("fmt"; "net"; "os")
func main() {
for _, h := range []string{
"cloudcode-pa.googleapis.com", // ALLOWLISTED
"play.googleapis.com", // ALLOWLISTED
"daily-cloudcode-pa.googleapis.com", // not on allowlist
} {
if ips, err := net.LookupHost(h); err != nil {
fmt.Fprintf(os.Stderr, "FAIL %s: %v\n", h, err)
} else {
fmt.Printf("OK %s: %v\n", h, ips)
}
}
}
GO
$ go run "$TMPDIR/dnstest.go"
FAIL cloudcode-pa.googleapis.com: lookup cloudcode-pa.googleapis.com: no such host
FAIL play.googleapis.com: lookup play.googleapis.com: no such host
FAIL daily-cloudcode-pa.googleapis.com: lookup daily-cloudcode-pa.googleapis.com: no such host
$ GODEBUG=netdns=cgo go run "$TMPDIR/dnstest.go"
go package net: GODEBUG setting forcing use of the cgo resolver
FAIL cloudcode-pa.googleapis.com: lookup cloudcode-pa.googleapis.com: no such host
FAIL play.googleapis.com: lookup play.googleapis.com: no such host
FAIL daily-cloudcode-pa.googleapis.com: lookup daily-cloudcode-pa.googleapis.com: no such host
Both the pure-Go path (Go reads /etc/resolv.conf and makes UDP queries directly) and the cgo path (Go calls libc's getaddrinfo) fail. The macOS resolver does not honor HOSTALIASES for FQDNs, so that workaround doesn't apply either.
Diagnosis
curl and nslookup are exempt from whatever DNS-blocking the sandbox applies to general-purpose binaries. Go binaries are not. The pattern is consistent with a sandbox profile that admits dns.proc.dyn.allow for specific binary paths (/usr/bin/curl, /usr/bin/nslookup, /usr/bin/dig) but defaults to deny for everything else, regardless of which host the call would resolve to.
Impact
Any Go-based CLI that needs network access fails inside the Claude Code Bash sandbox even when its endpoints are explicitly on the allowedHosts list. Concrete blocked tools I've encountered:
agy(Google Antigravity CLI, used by/oraclein abitai-stack for the Gemini voice in council mode)- Likely many others:
gcloudcomponents,hashicorp/*CLIs, anything written in Go
The failure mode is silent: agy exits 0 with empty stdout and a log file full of dial tcp: lookup cloudcode-pa.googleapis.com: no such host. The caller has no way to distinguish "the model declined to respond" from "the sandbox blocked the network."
I worked around this on the abitai-stack side by adding inline detection that inspects agy's log file after each call and emits a stderr signal (ANTIGRAVITY_SANDBOX_DNS_BLOCKED) when it sees the pattern — see tachyonlabs-ai/abitai-stack#104. But the workaround is per-binary and doesn't help other Go tools.
Proposed fix
Permit DNS resolution for allowedHosts regardless of which binary makes the call. Either:
- Filter at the DNS layer, not at the binary path. If a hostname is on
allowedHosts, let any process resolve it. - Add an explicit allowlist of resolver-capable binaries that includes Go's runtime DNS path. (Less clean — Go binaries don't share a single executable path.)
Option 1 is the right fix. The current behavior makes the allowedHosts setting half-effective: TCP connections to the listed hosts succeed, but DNS resolution from anything other than libc + a small allowlist of binaries fails, so most non-trivial network code can't reach the hosts the user is supposedly allowed to reach.
Workaround for now
Users hitting this in their own Bash sessions can:
- Run the affected Go binary from an unsandboxed terminal (system Terminal/iTerm, not Claude Code).
- Use a tool with a non-Go DNS path (e.g.
curl) where one exists. - For
/oracleusers specifically: skip Antigravity with/oracle --via codexor/oracle --via qwen(PR #104 detects the block automatically and council mode degrades to 2-of-3).
Environment
- Platform:
darwin25.5.0 (arm64) - Shell:
zsh5.9 - Go:
1.26.3 darwin/arm64 - Affected binary observed in:
agy1.0.1 (Google Antigravity CLI, installed to~/.local/bin/agy) - Sandbox config visible to me via the system prompt:
"allowedHosts":[..., "cloudcode-pa.googleapis.com", "oauth2.googleapis.com", "play.googleapis.com", "storage.googleapis.com", ...]
Happy to test a fix or provide more reproductions. The minimal Go program above reproduces it in ~10 seconds.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗