fix: use wildcard in allowLocalBinding seatbelt rules for IPv6 dual-stack compatibility

Modern runtimes like Java create IPv6 dual-stack sockets by default.
When binding such a socket to 127.0.0.1, the kernel represents the
address as ::ffff:127.0.0.1 (IPv4-mapped IPv6). macOS Seatbelt's
"localhost" filter only matches 127.0.0.1 and ::1, not the
IPv4-mapped variant, causing bind() to fail with EPERM.

Seatbelt only supports two host values in IP filters: "localhost"
and "*". Since we can't specify ::ffff:127.0.0.1 explicitly, change
to (local ip "*:*"). This is safe because the (local ip) filter
matches the LOCAL endpoint of connections — internet-bound traffic
originates from non-loopback interfaces, so it remains blocked by
the (deny default) rule.

Fixes: https://github.com/anthropics/claude-code/issues/18545
This commit is contained in:
Dylan Conway
2026-02-09 13:36:43 -08:00
parent 4fad8fa35d
commit cd5821669c

View File

@@ -492,10 +492,17 @@ function generateSandboxProfile({
profile.push('(allow network*)')
} else {
// Allow local binding if requested
// Use "*:*" instead of "localhost:*" because modern runtimes (Java, etc.) create
// IPv6 dual-stack sockets by default. When binding such a socket to 127.0.0.1,
// the kernel represents it as ::ffff:127.0.0.1 (IPv4-mapped IPv6). Seatbelt's
// "localhost" filter only matches 127.0.0.1 and ::1, NOT ::ffff:127.0.0.1.
// Using (local ip "*:*") is safe because it only matches the LOCAL endpoint —
// internet-bound connections originate from non-loopback interfaces, so they
// remain blocked by (deny default).
if (allowLocalBinding) {
profile.push('(allow network-bind (local ip "localhost:*"))')
profile.push('(allow network-inbound (local ip "localhost:*"))')
profile.push('(allow network-outbound (local ip "localhost:*"))')
profile.push('(allow network-bind (local ip "*:*"))')
profile.push('(allow network-inbound (local ip "*:*"))')
profile.push('(allow network-outbound (local ip "*:*"))')
}
// Unix domain sockets for local IPC (SSH agent, Docker, etc.)
if (allowAllUnixSockets) {