From 259f6f8091bd4c5bf794223a5544d9053aa86c97 Mon Sep 17 00:00:00 2001 From: Landon Cox Date: Tue, 31 Mar 2026 20:04:34 -0700 Subject: [PATCH 1/3] fix: disable IPv6 in agent container to prevent squid proxy bypass Always disable IPv6 via sysctl in setup-iptables.sh regardless of ip6tables availability. The awf-net Docker network is IPv4-only and Squid only listens on IPv4, so IPv6 serves no purpose in the agent container. Leaving it enabled causes Node.js happy-eyeballs to prefer IPv6, resulting in connections to ::1 that Squid rejects with transaction-end-before-headers. Also add IPv6 listeners to Squid config (http_port [::]:3128) as defense-in-depth, so any residual IPv6 traffic is handled rather than silently rejected. Closes #1543 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- containers/agent/setup-iptables.sh | 15 +++++++++++---- src/squid-config.ts | 10 +++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/containers/agent/setup-iptables.sh b/containers/agent/setup-iptables.sh index d8dbe55ee..d9a7a1a21 100644 --- a/containers/agent/setup-iptables.sh +++ b/containers/agent/setup-iptables.sh @@ -31,12 +31,19 @@ IP6TABLES_AVAILABLE=false if has_ip6tables; then IP6TABLES_AVAILABLE=true echo "[iptables] ip6tables is available" -else - echo "[iptables] WARNING: ip6tables is not available, disabling IPv6 via sysctl to prevent unfiltered bypass" - sysctl -w net.ipv6.conf.all.disable_ipv6=1 2>/dev/null || echo "[iptables] WARNING: failed to disable IPv6 (net.ipv6.conf.all.disable_ipv6)" - sysctl -w net.ipv6.conf.default.disable_ipv6=1 2>/dev/null || echo "[iptables] WARNING: failed to disable IPv6 (net.ipv6.conf.default.disable_ipv6)" fi +# Always disable IPv6 in the agent network namespace. +# Squid listens on IPv4 only and the Docker awf-net network is IPv4-only, +# so IPv6 serves no purpose. Disabling it prevents: +# 1. DNS returning AAAA records → Node.js happy-eyeballs preferring IPv6 → connection failures +# 2. IPv6 connections bypassing IPv4-only iptables DNAT rules to Squid +# 3. Claude Code/other agents connecting via ::1 which Squid cannot handle +# See: https://github.com/github/gh-aw-firewall/issues/1543 +echo "[iptables] Disabling IPv6 to prevent proxy bypass (Squid is IPv4-only)..." +sysctl -w net.ipv6.conf.all.disable_ipv6=1 2>/dev/null || echo "[iptables] WARNING: failed to disable IPv6 (net.ipv6.conf.all.disable_ipv6)" +sysctl -w net.ipv6.conf.default.disable_ipv6=1 2>/dev/null || echo "[iptables] WARNING: failed to disable IPv6 (net.ipv6.conf.default.disable_ipv6)" + # Get Squid proxy configuration from environment SQUID_HOST="${SQUID_PROXY_HOST:-squid-proxy}" SQUID_PORT="${SQUID_PROXY_PORT:-3128}" diff --git a/src/squid-config.ts b/src/squid-config.ts index 73deae6a8..6f95c25a1 100644 --- a/src/squid-config.ts +++ b/src/squid-config.ts @@ -183,12 +183,19 @@ function generateSslBumpSection( # HTTP port with SSL Bump enabled for HTTPS interception # This handles both HTTP requests and HTTPS CONNECT requests +# Listen on both IPv4 and IPv6 as defense-in-depth (see #1543) http_port 3128 ssl-bump \\ cert=${caFiles.certPath} \\ key=${caFiles.keyPath} \\ generate-host-certificates=on \\ dynamic_cert_mem_cache_size=16MB \\ options=NO_SSLv3,NO_TLSv1,NO_TLSv1_1 +http_port [::]:3128 ssl-bump \\ + cert=${caFiles.certPath} \\ + key=${caFiles.keyPath} \\ + generate-host-certificates=on \\ + dynamic_cert_mem_cache_size=16MB \\ + options=NO_SSLv3,NO_TLSv1,NO_TLSv1_1 # SSL certificate database for dynamic certificate generation # Using 16MB for certificate cache (sufficient for typical AI agent sessions) @@ -420,7 +427,8 @@ export function generateSquidConfig(config: SquidConfig): string { // Port configuration: Use normal proxy mode (not intercept mode) // With targeted port redirection in iptables, traffic is explicitly redirected // to Squid on specific ports (80, 443, + user-specified), maintaining defense-in-depth - let portConfig = `http_port ${port}`; + // Listen on both IPv4 and IPv6 as defense-in-depth (see #1543) + let portConfig = `http_port ${port}\nhttp_port [::]:${port}`; // For SSL Bump, we need to check hasPlainDomains and hasPatterns for the 'both' protocol domains // since those are the ones that go into allowed_domains / allowed_domains_regex ACLs From 62675ba27cbf3536b5686043ed60bc458669cadd Mon Sep 17 00:00:00 2001 From: Landon Cox Date: Tue, 31 Mar 2026 20:38:39 -0700 Subject: [PATCH 2/3] Update src/squid-config.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/squid-config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/squid-config.ts b/src/squid-config.ts index 6f95c25a1..c1fc1bf00 100644 --- a/src/squid-config.ts +++ b/src/squid-config.ts @@ -183,7 +183,7 @@ function generateSslBumpSection( # HTTP port with SSL Bump enabled for HTTPS interception # This handles both HTTP requests and HTTPS CONNECT requests -# Listen on both IPv4 and IPv6 as defense-in-depth (see #1543) +# Listen on both IPv4 and IPv6 as defense-in-depth (see: gh-aw-firewall issue #1543) http_port 3128 ssl-bump \\ cert=${caFiles.certPath} \\ key=${caFiles.keyPath} \\ From ae173c028e26a5d4ae1bbfc489cfb4266160a5d8 Mon Sep 17 00:00:00 2001 From: Landon Cox Date: Tue, 31 Mar 2026 20:38:54 -0700 Subject: [PATCH 3/3] Update containers/agent/setup-iptables.sh Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- containers/agent/setup-iptables.sh | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/containers/agent/setup-iptables.sh b/containers/agent/setup-iptables.sh index d9a7a1a21..28fb0d49b 100644 --- a/containers/agent/setup-iptables.sh +++ b/containers/agent/setup-iptables.sh @@ -34,13 +34,17 @@ if has_ip6tables; then fi # Always disable IPv6 in the agent network namespace. -# Squid listens on IPv4 only and the Docker awf-net network is IPv4-only, -# so IPv6 serves no purpose. Disabling it prevents: -# 1. DNS returning AAAA records → Node.js happy-eyeballs preferring IPv6 → connection failures -# 2. IPv6 connections bypassing IPv4-only iptables DNAT rules to Squid -# 3. Claude Code/other agents connecting via ::1 which Squid cannot handle -# See: https://github.com/github/gh-aw-firewall/issues/1543 -echo "[iptables] Disabling IPv6 to prevent proxy bypass (Squid is IPv4-only)..." +# The Docker awf-net network and our iptables DNAT rules are IPv4-based, so +# IPv6 connectivity would serve mainly as a way to bypass those controls. +# Disabling IPv6 here: +# 1. Removes IPv6 addresses/routes so traffic cannot egress over IPv6 paths +# 2. Prevents IPv6 connections (including ::1 loopback) that would not be +# intercepted by IPv4-only iptables DNAT rules to the Squid proxy +# 3. Avoids applications preferring IPv6 paths that would bypass or conflict +# with the intended IPv4 proxy/NAT behavior (e.g., Happy Eyeballs) +# Note: This does not change upstream DNS responses; it only disables IPv6 +# connectivity inside the container. See: https://github.com/github/gh-aw-firewall/issues/1543 +echo "[iptables] Disabling IPv6 inside container to prevent IPv6 egress / proxy bypass..." sysctl -w net.ipv6.conf.all.disable_ipv6=1 2>/dev/null || echo "[iptables] WARNING: failed to disable IPv6 (net.ipv6.conf.all.disable_ipv6)" sysctl -w net.ipv6.conf.default.disable_ipv6=1 2>/dev/null || echo "[iptables] WARNING: failed to disable IPv6 (net.ipv6.conf.default.disable_ipv6)"