[Security Review] 🔒 Daily Security Review: AWF Codebase Threat Model & Analysis (2026-07-10) #6083
Replies: 2 comments
-
|
🔮 The ancient spirits stir: the Codex 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... the smoke test agent was here, and the omens of GitHub are clear. 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.
Uh oh!
There was an error while loading. Please reload this page.
-
📊 Executive Summary
This review analyzed 419 source files / ~64,500 lines of security-critical code across the gh-aw-firewall (AWF) codebase. Overall, the security posture is strong. The architecture-in-depth approach — host iptables, container iptables, Squid ACL, capability drops, seccomp, and DNS restriction — provides overlapping controls.
Key metrics:
npm audit)SCMP_ACT_ERRNOdefault)%ruURL field is not JSON-escaped (acknowledged in code comments)unconfinedon the agent container (SYS_ADMIN required for procfs mount)🔍 Findings from Firewall Escape Test
The
escape-test-summary.txtfile was empty (0 bytes) in this run — no prior escape test results were available to correlate with. Analysis is based entirely on static code review.🛡️ Architecture Security Analysis
Network Security Assessment
Strengths:
src/host-iptables-rules.ts) + agent container OUTPUT chain (containers/agent/setup-iptables.sh)sysctl net.ipv6.conf.all.disable_ipv6=1) to prevent Happy Eyeballs bypass172.30.0.0/24); container IPs are staticGap — ICMP not blocked in agent OUTPUT filter chain:
Evidence:
The agent container's
iptablesOUTPUT filter chain explicitly drops TCP and UDP but never sets the OUTPUT default policy to DROP nor adds an explicitICMP DROPrule. The host-level DOCKER-USER chain (addBlockRules()insrc/host-iptables-rules.ts:287) will catch ICMP exiting the bridge via its final REJECT rule, but within the same subnet (e.g. agent → squid-proxy via172.30.0.0/24), ICMP traverses within the bridge and is not subject to the FORWARD/DOCKER-USER hook — it is only filtered by the agent's own OUTPUT chain. This allows unrestricted ICMP (ping, traceroute, potentially covert channel via ICMP echo payloads) from the agent to any IP on the same bridge or the gateway.Severity: Medium — Not a direct data exfiltration path (ICMP payload is typically 64 bytes, and external traffic does hit DOCKER-USER), but allows covert signaling within the AWF network namespace and information gathering (ping timing oracles, traceroute path discovery).
Mitigation: Add
iptables -A OUTPUT -p icmp -j DROPbefore the final TCP/UDP drop rules inconfigure_filter_chain().Container Security Assessment
Strengths:
cap_add: [SYS_CHROOT, SYS_ADMIN]at compose level only for setup —entrypoint.shdrops both viacapsh --drop=cap_sys_chroot,cap_sys_adminbefore user code executes (line ~1320, 1355)NET_RAWexplicitly dropped from agent at compose level (src/services/agent-service.ts:84) — prevents raw socket creation (prevents some iptables bypass)SYS_PTRACE,SYS_MODULE,SYS_RAWIO,MKNODdroppedno-new-privileges:trueon all containersSCMP_ACT_ERRNO— only 341 explicitly allowed syscallsnetwork_mode: service:agent(shares namespace) but is a separate container withcap_drop: ALLexceptNET_ADMIN, NET_RAWNoted weakness — Sensitive syscalls allowed in seccomp despite capability drop:
These are needed during setup (entrypoint.sh runs as root with SYS_ADMIN/SYS_CHROOT before dropping). However, since
no-new-privileges:trueis set and capabilities are dropped before user code executes, these syscalls will fail at user code runtime. This is defense-in-depth — the seccomp profile could be tightened for user code by having a two-phase seccomp (stricter after cap drop), but that is a significant architectural change.Noted weakness — AppArmor
unconfinedon agent:AppArmor is disabled because
mount -t proc(for/host/procwithhidepid=2) is blocked by Docker's default AppArmor profile. The comment correctly notes that SYS_ADMIN is dropped before user code runs. While accepted as a design tradeoff, it does mean that if capsh fails silently or is bypassed, there is no AppArmor backstop.Domain Validation Assessment
Strengths:
validateDomainOrPattern()insrc/domain-validation.tsrejects injection characters:[\s\0"';#\]`assertSafeForSquidConfig()insrc/squid/domain-acl.tsprovides a second defense-in-depth check at interpolation time*,*.*, patterns of only*/.*.*.com) rejected*→[a-zA-Z0-9.-]*in regex (safe from ReDoS via RFC 1035 character class)acl dst_ipv4 dstdom_regex ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$Noted weakness — Audit JSONL URL field not JSON-escaped:
A crafted URL like
(allowed.domain.com/redacted),"injected":"evil"could inject arbitrary JSON into theaudit.jsonllog. This does not affect runtime security (Squid ACL enforcement is separate from logging), but downstream SIEM tools that parse the audit log as JSONL may misparse entries or be confused by log injection.Severity: Low — Log integrity issue, not a runtime security bypass.
Input Validation Assessment
Strengths:
execa()calls pass arrays (never shell strings) — confirmedshell: trueis absent in all TypeScript sourcesrc/host-iptables-validation.ts) and Bash (is_valid_port_spec()) with shared test fixturetests/port-spec-fixtures.jsonAWF_USER_UID/AWF_USER_GIDvalidated as numeric and non-zero inentrypoint.sh:18-39agent-service.ts:76,90setup-iptables.sh:479-482%ruURL field; downstream SIEM tools may misparseconfig-generator.ts:97setup-iptables.sh:configure_dns_nat_rules()agent-service.ts:102forwarded_for delete+via offremoves client identity — this is correct for privacy but means logs cannot attribute requests to specific processesconfig-generator.ts:148-149mount,clone,unshare,setns(needed for setup); if capability check logic is bypassed, these could be used for namespace escapeseccomp-profile.jsoncontainers/api-proxy/--log-uidcaptures UID, not PID); agent can claim it did not make a specific connectionsetup-iptables.sh:472-478AGENTS.mdarchitecture notes🎯 Attack Surface Map
--allow-domainsCLI argvalidateDomainOrPattern()+assertSafeForSquidConfig()dual validation%ru--enable-api-proxyredactSecrets()on config logs--enable-host-accessflag📋 Evidence Collection
Command: Seccomp profile analysis
Command: ICMP gap evidence
Command: npm audit
Command: shell:true absence check
Command: Capability configuration
✅ Recommendations
🔴 Medium — Address Soon
1. Add explicit ICMP DROP rule in agent OUTPUT filter chain
In
containers/agent/setup-iptables.sh, insideconfigure_filter_chain(), add before the final TCP/UDP drop rules:2. Consider setting OUTPUT default policy to DROP
This ensures any protocol not explicitly covered (SCTP, GRE, etc.) is dropped by default rather than relying on exhaustive per-protocol rules.
🟡 Low — Plan to Address
3. Fix JSONL audit log injection (URL field)
In
src/squid/config-generator.ts:97, URL-encode or omit the%rufield, or post-process the log. A minimal mitigation is to document the limitation in the audit format schema and add a validation step in log consumer tooling.4. Tighten seccomp ALLOW list for user code phase
If a dual-phase approach is feasible (strict seccomp for user code, permissive during setup), remove
mount,unshare,setns,clonefrom the profile after setup completes. This is an architectural challenge given the current single-container model.5. Document AppArmor unconfined tradeoff
The
apparmor:unconfinedsetting inagent-service.tsis necessary and mitigated by capability drops. Add a comment in the security-critical path noting that a custom AppArmor profile allowing onlyprocmounts would be a future hardening improvement.🟢 Low / Nice to Have
6. Add a rate-limit on ICMP even if not dropped — If blocking ICMP breaks legitimate use cases, rate-limit it.
7. Consider explicit
iptables -A OUTPUT -j LOG; -j DROPcatch-all — Log and drop all unmatched protocols (not just TCP/UDP).8. Pin dependency versions — Currently only 5 runtime dependencies; continue to keep the surface minimal.
📈 Security Metrics
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