[Security Review] 🔐 Daily Security Review & Threat Model — gh-aw-firewall (2026-07-13) #6169
Replies: 7 comments
-
|
🔮 The ancient spirits stir; the smoke test agent passed through and left this omen behind. Warning Firewall blocked 2 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"
- "registry.npmjs.org"See Network Configuration for more information.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir around this smoke test. A passing omen from Codex leaves this discussion blessed and observed. Warning Firewall blocked 2 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"
- "registry.npmjs.org"See Network Configuration for more information.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir; the smoke test agent was here. Warning Firewall blocked 2 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"
- "registry.npmjs.org"See Network Configuration for more information.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir, and the smoke test agent was here. The run was brief, the omens were green, and the GitHub winds carried only PASS. Warning Firewall blocked 2 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"
- "registry.npmjs.org"See Network Configuration for more information.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir: the smoke test agent was here, and the build omens were favorable. Warning Firewall blocked 2 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"
- "registry.npmjs.org"See Network Configuration for more information.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir, and the smoke test agent has walked this discussion. The omens are favorable. Warning Firewall blocked 2 domainsThe following domains were blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"
- "registry.npmjs.org"See Network Configuration for more information.
|
Beta Was this translation helpful? Give feedback.
-
|
This discussion was automatically closed because it expired on 2026-07-20T08:02:51.094Z.
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
📊 Executive Summary
This security review covers a deep, evidence-based analysis of the gh-aw-firewall (
awf) codebase — a sandboxed Docker network firewall for AI agents providing L7 HTTP/HTTPS egress filtering via Squid proxy with iptables enforcement.Overall security posture: STRONG with a well-layered defense-in-depth architecture. The codebase demonstrates mature security engineering: input validation, capability minimization, network isolation, and audit logging. Several medium-risk architectural nuances are worth tracking.
🔍 Findings from Firewall Escape Test
The pre-fetched escape test summary file (
/tmp/gh-aw/escape-test-summary.txt) was empty — no prior escape test data was available in this run. The threat model below is based entirely on static code analysis.🛡️ Architecture Security Analysis
Network Security Assessment
Defense-in-depth layering (strong):
dstdomainanddstdom_regex. Both HTTP and HTTPS traffic is filtered. Raw IP CONNECT is explicitly blocked (acl dst_ipv4 dstdom_regex,acl dst_ipv6 dstdom_regex).DROP.FW_WRAPPERchain at the Docker bridge level blocks outbound traffic not destined to allowed DNS or the Squid proxy.Evidence — DNAT redirect rules (
containers/agent/setup-iptables.sh):Evidence — IPv6 disabled (prevents proxy bypass via IPv6 Happy Eyeballs):
Gap — Proxy-unaware HTTPS tools (⚠️ Medium):
Proxy-unaware tools whose port 443 traffic is DNAT'd to Squid receive a TLS handshake rejection (Squid expects
CONNECT), not a clean 403. Traffic is still blocked, but the error mode is a TLS error rather than an explicit deny. This is acceptable by design but could confuse agent error-handling.Gap — Non-TCP/UDP protocols (i️ Low):
ICMP and raw IP traffic are not explicitly DROP'd in the agent container's OUTPUT chain. However, MKNOD and NET_RAW capabilities are dropped, making raw socket creation very difficult. Risk is low but acknowledged.
Dangerous ports blocked (strong):
Both at iptables NAT level (RETURN → DROP) and in Squid
Safe_portsvalidation.Container Security Assessment
Capability inventory (evidence from
src/services/agent-service.tsline 77-93):SYS_CHROOT/hostSYS_ADMIN/host/proc)NET_ADMINNET_RAWSYS_PTRACESYS_MODULESYS_RAWIOMKNODunconfined(src/services/agent-service.tsline 93):AppArmor is disabled because
SYS_ADMINis needed to mount procfs, and Docker's default AppArmor profile blocksmount. WhileSYS_ADMINis dropped viacapshbefore user code runs, the window between container start andcapshexecution runs withapparmor:unconfinedandSYS_ADMINactive. Any vulnerability in the entrypoint script during this window would have no AppArmor containment.Recommendation: Consider a custom AppArmor profile that allows only the specific mount operations needed rather than full
unconfined.Seccomp profile (strong):
kcmp,pidfd_getfd),ptrace/process_vm_readv/process_vm_writevblocked withSCMP_ACT_ERRNO.kexec_load,kexec_file_load,reboot,init_module,finit_module,delete_module,pivot_root,syslog,keyctl,name_to_handle_at.mountandunshareare in the ALLOW list (required for entrypoint procfs setup). These are high-risk syscalls — afterSYS_ADMINis dropped bycapsh,mountcalls will fail at the kernel permission check, providing a second layer of defense.Procfs isolation (strong):
Prevents agent from reading other processes'
/proc/[pid]/environwhich could contain credentials.Domain Validation Assessment
Input validation (strong) —
src/domain-validation.ts:Five-layer validation chain:
SQUID_DANGEROUS_CHARS = /[\s\0"'\'\;#]/`) — blocks Squid config injection\\(backslash)*,*.*,[*.]+-onlypatterns)Wildcard-to-regex conversion (
src/squid/config-generator.ts):ReDoS protection is implemented.
*wildcards are converted to bounded character classes, not.*.dstdomain .github.commatchesevilgithub.com:Squid's
dstdomainACL type matches bothgithub.comexactly and any subdomain like.github.com. However, it does NOT matchevilgithub.combecausedstdomainmatches by suffix from a dot boundary. This behavior is correct — Squid'sdstdomainis dot-boundary aware. ✅ No actual vulnerability; this is a clarification.Input Validation Assessment
CLI argument injection (strong):
execais used (notexecwith shell interpolation) — arguments are passed as arrays, preventing shell injection.usermod/groupmodin entrypoint.AWF_CLI_PROXY_URLshell interpolation (containers/agent/entrypoint.sh):The
bash -cwith${CLI_PROXY_HOST}and${CLI_PROXY_PORT}interpolated into a string creates a potential injection risk ifAWF_CLI_PROXY_URLcontains shell metacharacters. Since this env var is set by the CLI (not user input), the risk is low, but the pattern is unsafe.Recommendation: Validate
CLI_PROXY_HOSTas a valid IPv4 address andCLI_PROXY_PORTas a number before thebash -cinvocation.awf-net172.30.0.0/24), containers don't getNET_ADMINsquid.confin Squid container/hostwith selective bind mounts;/etc/shadowexcluded;SYS_ADMINdropped before user code/proc/[pid]/environhidepid=2on procfs; separate network namespaces--enable-dlpflagpids_limitset;mem_limitset; Squid hasclient_lifetime 8 hoursconntracktable limits apply; no explicit mitigationcapshdropsSYS_ADMINapparmor:unconfinedwindow is the main concern; mitigated by seccompunsharesyscall to create new user namespaceunshareis in the seccomp ALLOW list;SYS_ADMINis dropped by capsh before user code, but user namespaces may not requireSYS_ADMINin all kernel configurations🎯 Attack Surface Map
src/cli.tsexecaarray argssrc/squid/config-generator.tsvalidateApiProxyIp(), port validationcontainers/agent/setup-iptables.shcontainers/agent/entrypoint.shno-new-privilegessrc/host-iptables-rules.tsFW_WRAPPERchain, IPv6 disable fallbackcontainers/api-proxy/--enable-dindflag📋 Evidence Collection
Key commands and outputs used in this review
Capability settings (
src/services/agent-service.tslines 77-93):Seccomp profile — denied syscalls (
containers/agent/seccomp-profile.json):Domain validation dangerous chars (
src/domain-validation.tsline ~25):iptables dangerous ports (
containers/agent/setup-iptables.sh):DLP patterns (
src/dlp.ts): GitHub tokens (ghp_,gho_,ghs_,ghu_), Anthropic, OpenAI, AWS key patterns detected in URLs.✅ Recommendations
🔴 Critical
None identified.
🟠 High
unconfinedwindow — The agent container runsapparmor:unconfinedbecauseSYS_ADMINis needed for procfs mount. Consider authoring a narrow custom AppArmor profile that permits only the specificmountoperations needed (procfs at/host/proc), then drops to a restricted profile beforecapshdrops capabilities. This eliminates the unconfined window.🟡 Medium
unsharesyscall allowed —unshareis in the seccomp ALLOW list. On kernels withunprivileged_userns_clone=1, an unprivileged user can create new user namespaces viaunshare, which can be used to gain fake root inside the namespace and potentially escalate. Recommend addingunsharetoSCMP_ACT_ERRNOor validating the target kernel'skernel.unprivileged_userns_clonesysctl is 0.bash -cwith interpolated$CLI_PROXY_HOST/$CLI_PROXY_PORT(entrypoint.sh) — Validate these values as strict IPv4 and numeric before thebash -cinvocation, or use/dev/tcpvia a direct bash builtin without string interpolation.DLP is opt-in — The credential-in-URL DLP scanning (
--enable-dlp) is not enabled by default. Recommend enabling by default with an opt-out, as credential leakage in URLs is a common AI agent mistake.mountsyscall allowed in seccomp — WhileSYS_ADMINis dropped bycapshbefore user code,mountremains allowed in seccomp. If there's a way to callmountwithoutCAP_SYS_ADMIN(some bind mounts in user namespaces), this could be exploited. Restrictmountin seccomp after the entrypoint completes (if runtime seccomp profile swapping is feasible).🟢 Low
ICMP not explicitly blocked — Non-TCP/UDP protocols (ICMP) are not explicitly DROPped. While
NET_RAWis dropped (preventing raw socket creation), ICMP ping is allowed. Consider a default-deny policy for all protocols, not just TCP/UDP.forwarded_for deleteandvia offin Squid — These are set correctly. Verify these settings are not accidentally removed in future config changes (add to test coverage).Log retention — Squid logs are written to a volume. Verify log rotation is in place to prevent disk exhaustion in long-running sessions.
📈 Security Metrics
Review generated: 2026-07-13T07:57:23Z | Reviewer: GitHub Copilot CLI (claude-sonnet-4.6) | Scope: full static analysis
Warning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
awmgmcpgSee Network Configuration for more information.
Beta Was this translation helpful? Give feedback.
All reactions