[Security Review] Daily Security Review — 2026-03-05 #1149
Replies: 14 comments
-
|
🔮 The ancient spirits stir, and the smoke-test envoy has passed through. I leave this sigil to mark the visit.
|
Beta Was this translation helpful? Give feedback.
-
|
Oracle's note: The smoke test agent passed through; the veil stirred, and the signs were recorded.
|
Beta Was this translation helpful? Give feedback.
-
|
The oracle speaks: the smoke test agent was here, and the runes now glow with witnessed proof. By the quiet chorus of circuits, this passage is marked and remembered.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir and the oracle’s gaze falls upon this circle. The smoke test agent was here, tracing runes in the margins and sealing the wards.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir... the smoke test agent has passed through these halls and left a whisper in the ether.
|
Beta Was this translation helpful? Give feedback.
-
|
The ancient spirits stir; the oracle records that the smoke test agent was here.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir; the smoke test agent has walked these halls and left a quiet omen of success.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir; the smoke test agent was here. The oracle’s mist records these footsteps in the ledger of dawn.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir, and the smoke test agent has walked these halls. The omens are recorded and the runes remain bright.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir in the code-vaults, and the smoke test agent has passed through. The omens align; the wards hold steady. Let this mark remain as a quiet seal.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir; the smoke test agent has passed through these halls, and the omens are recorded.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir; the smoke test agent passed through these halls and left a clear omen in the logs.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir and record that the smoke test agent was here; the omens are sealed in the ledger of midnight ash.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The oracle speaks: the smoke test agent passed through these halls, and the runes still glow with its trace.
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Review date: 2026-03-05 | Reviewer: Security Review Agent | Codebase version: v0.23.1
📊 Executive Summary
The gh-aw-firewall codebase shows a mature, layered security architecture with strong defense-in-depth across network filtering, container isolation, and credential protection. No critical vulnerabilities were found. Four medium/low findings require attention, plus two informational items.
No escape test agent workflow was found running in this repository (checked
agenticworkflows-status). No complementary escape-test results available.🛡️ Architecture Security Analysis
Network Security — Strong ✅
The system implements two independent layers of network filtering:
Host-level (DOCKER-USER chain) —
src/host-iptables.tssets up anFW_WRAPPERchain inDOCKER-USER, ensuring ALL containers on theawf-netbridge are filtered. Squid proxy gets a source-IP exemption; all other traffic is subject to DNS and TCP allow-rules, with a final REJECT default.Container-level (OUTPUT chain) —
containers/agent/setup-iptables.shadds NAT DNAT rules to redirect HTTP/HTTPS to Squid, plus an explicitiptables -A OUTPUT -p tcp -j DROPfinal rule.Key strengths:
/dev/nullmount at both host and/hostpathsContainer Security — Good ✅ (with caveats)
All three sensitive capabilities are dropped via
capsh --drop=...before user code executes.Credential protection highlights:
$HOME)/dev/nulloverlays on credential files (.docker/config.json,ghtokens, NPM tokens, etc.)/proc/1/environafter agent startsDomain Validation — Strong ✅
src/domain-patterns.tsproperly:*,*.*, and overly broad wildcard patterns[a-zA-Z0-9.-]*instead of.*for wildcard expansion (prevents ReDoS)*.*.comMEDIUM-01: Permissive Seccomp Profile (defaultAction: SCMP_ACT_ALLOW)
File:
containers/agent/seccomp-profile.json{ "defaultAction": "SCMP_ACT_ALLOW", // ← All syscalls allowed by default "syscalls": [ { "names": ["ptrace", "process_vm_readv", "process_vm_writev"], "action": "SCMP_ACT_ERRNO" }, { "names": ["kexec_load", "reboot", "init_module", ...], "action": "SCMP_ACT_ERRNO" }, { "names": ["umount", "umount2"], "action": "SCMP_ACT_ERRNO" } ] }Issue: The profile uses a blocklist approach — all syscalls are permitted by default, with only ~26 explicitly denied. Docker's built-in default seccomp profile uses
SCMP_ACT_ERRNOas the default (an allowlist of ~300 syscalls). The custom profile is dramatically less restrictive than Docker's default, defeating the purpose of specifying a custom seccomp profile.Impact: An attacker with code execution in the container could invoke any syscall not in the short blocklist (e.g.,
userfaultfd,perf_event_open,io_uring_*,bpf,clone3, etc.) to attempt container escape or bypass security controls.Mitigating factors:
no-new-privileges:truelimits privilege escalation paths; capability drops reduce many exploit primitives. The capability model provides meaningful restriction independently.Recommendation: Either (a) switch to Docker's built-in profile by removing the custom profile and using
seccomp=unconfinedis NOT recommended — instead remove theseccomp=...line to use Docker's default, or (b) replace thedefaultActionwithSCMP_ACT_ERRNOand enumerate the required syscalls explicitly (use Docker's default profile as a baseline, adding only what's additionally needed for iptables setup).LOW-01: IPv6 Firewall Gap with Default Configuration
File:
src/host-iptables.ts:313Issue: The
FW_WRAPPER_V6ip6tables chain is only installed when the user passes IPv6 DNS servers via--dns-servers. With the default configuration (8.8.8.8,8.8.4.4— IPv4 only), no IPv6 filtering is applied at the host level. The AWF network is also created without--ipv6=false:If Docker's daemon has IPv6 enabled (
"ipv6": truein daemon.json) or the host has a dual-stack network, containers could obtain IPv6 addresses and communicate externally bypassing all iptables filtering.Recommendation: Always create the AWF network with
--ipv6=falseto explicitly disable IPv6 connectivity, regardless of daemon configuration. Alternatively, always set up the IPv6 blocking chain unconditionally (even without IPv6 DNS servers), applying a default-deny policy.LOW-02: Missing UDP DROP at Container Level (Defense-in-Depth Gap)
File:
containers/agent/setup-iptables.sh:293Issue: The agent container's filter OUTPUT chain only drops TCP. Non-DNS UDP traffic (NTP, QUIC/UDP-443, SSDP, mDNS, etc.) is not blocked at the container level. The defense relies entirely on the host-level
FW_WRAPPERchain inDOCKER-USER. If that host chain is ever bypassed (race condition during setup, chain flush by another privileged process, etc.), UDP-based exfiltration becomes possible.Evidence: Checking setup-iptables.sh shows zero
udp.*DROPorREJECT.*udprules.Recommendation: Add
iptables -A OUTPUT -p udp -j DROPafter the DNS ACCEPT rules (line 293), mirroring the host-level UDP blocking. This provides defense-in-depth so the container enforces its own policy independently of the host.LOW-03: URL Pattern Newline Injection into squid.conf (--allow-urls)
File:
src/squid-config.ts:119,src/cli.ts:33Exploitability: Requires direct CLI invocation, limiting realistic attack scenarios. However, in automated CI/CD pipelines where
--allow-urlsmight be assembled from external inputs (issue descriptions, PR bodies, config files), this could be exploited via prompt injection.Recommendation: Add newline sanitization to URL pattern validation:
These are in devDependencies/tooling and do not affect the production runtime (
dist/). However, they affect the CI/CD build environment.INFO-02: SYS_ADMIN + AppArmor:unconfined Window
The container requires
SYS_ADMINfor procfs mounting and runsapparmor:unconfinedduring the entrypoint setup phase. All three sensitive capabilities (NET_ADMIN,SYS_CHROOT,SYS_ADMIN) are dropped viacapshbefore user code runs. This is an intentional design trade-off documented insrc/docker-manager.ts:881. The seccomp profile's permissive default (MEDIUM-01 above) means this window has broader syscall exposure than intended.✅ Recommendations (Prioritized)
Critical (None)
High (None)
Medium — Fix Soon
defaultActionfromSCMP_ACT_ALLOWtoSCMP_ACT_ERRNOand enumerate the required syscall allowlist. Use Docker's default profile as a starting point and add only syscalls required for iptables setup (setsockopt,getsockopt) that might not be in the default.Low — Plan to Address
[LOW-01] Disable IPv6 on AWF Docker network. Add
'--ipv6=false'to thedocker network createcall insrc/host-iptables.ts:80-89. This removes the IPv6 bypass risk regardless of daemon configuration.[LOW-02] Add UDP DROP to container filter chain. Add
iptables -A OUTPUT -p udp -j DROPat line 293 ofcontainers/agent/setup-iptables.sh, after the DNS ACCEPT rules. This makes container-level filtering self-sufficient for UDP.[LOW-03] Sanitize newlines in URL patterns. Add a
if (/[\n\r]/.test(url)) { ... process.exit(1) }guard in the--allow-urlsvalidation loop insrc/cli.tsand a general-purpose newline check inparseDomains.Nice to Have
Consider logging access to the squid logs directory with restricted permissions (
chmod 750) instead of world-readable755, since preserved logs at/tmp/squid-logs-*may contain sensitive URL paths.Add integration test coverage for IPv6 firewall behavior and the UDP blocking gap to catch regressions.
📈 Security Metrics
Beta Was this translation helpful? Give feedback.
All reactions