[Security Review] ๐ Daily Security Review โ 2026-07-11 #6112
Replies: 2 comments
-
|
๐ฎ 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. 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 is a daily security review of the
gh-aw-firewallrepository as of 2026-07-11. The codebase implements a multi-layered defence: domain-allowlist enforcement via Squid proxy, iptables DNAT/FILTER rules, container capability restrictions, seccomp profiles, chroot isolation, and UID/GID remapping. The overall security posture is strong, with several deliberate defence-in-depth layers. No critical vulnerabilities were found. Several medium-severity hardening gaps and design-level risks are identified below.Key metrics:
entrypoint.shand 536-linesetup-iptables.shreviewed๐ Findings from Firewall Escape Test
The pre-fetched escape test summary (
/tmp/gh-aw/escape-test-summary.txt) was present but empty at the time of this review. No complementary escape-test data was available to cross-reference. Findings below are based solely on static code analysis.๐ก๏ธ Architecture Security Analysis
Network Security Assessment
Two-layer enforcement (host + container):
Host-level (
src/host-iptables-rules.ts): A dedicatedFW_WRAPPERiptables chain is inserted intoDOCKER-USERto filter traffic that originates from the AWF network bridge. Squid and DoH proxy sources are explicitly allowed; DNS is restricted to pre-validated nameservers; dangerous ports (22, 25, 445, 1433, 1521, 3306, 3389, 5432, 6379, 27017โ28017) are blocked.Container-level (
containers/agent/setup-iptables.sh, lines 405โ419): All port-80 and port-443 TCP egress is DNAT'd to Squid at172.30.0.10:3128. The iptables-init init container runs before the agent command starts and signals readiness via/tmp/awf-init/ready.Positive findings:
sysctl net.ipv6.conf.all.disable_ipv6=1(setup-iptables.sh line ~130), preventing IPv6 proxy bypass.CONNECTtunnelling; SSL Bump is opt-in.forwarded_for deleteandvia offare set in the generated Squid config (src/squid/config-generator.tslines 148โ149), preventing client IP leakage.Gap โ proxy-unaware HTTPS tools (medium):
When a tool does not honour
HTTPS_PROXY, its TLSClientHellois DNAT'd to Squid port 3128, which is listening in forward-proxy mode (notssl-bump interceptmode by default). Squid will reject the raw TLS with a connection error rather than a clean 403. The traffic is still blocked, but the error surface is different and could cause confusing agent behaviour. This is a known, accepted trade-off documented inAGENTS.md.Gap โ AppArmor unconfined (medium):
agent-service.tsline 93:AppArmor is set to
unconfinedon the agent container because Docker's default AppArmor profile blocksmount(needed for procfs at/host/proc). WhileSYS_ADMINis dropped viacapshbefore user code runs (entrypoint.sh line ~400), the container runs without AppArmor confinement for the initial entrypoint phase whereSYS_ADMINis still held. This is a hardening gap.Container Security Assessment
Capability model (
src/services/agent-service.ts):SYS_CHROOTandSYS_ADMINare explicitly dropped viacapsh --drop=cap_sys_chroot,cap_sys_adminbefore user code executes (entrypoint.sh lines ~399โ403 and ~1320). This is correct practice.NET_ADMINis never granted to the agent โ only to the separateawf-iptables-initinit container that shares the network namespace.UID/GID remapping (
containers/agent/entrypoint.shlines 12โ61):AWF_USER_UIDandAWF_USER_GIDare validated to be numeric and non-zero (non-root) before use.Seccomp: A custom seccomp profile is written to
workDir/seccomp-profile.jsonand applied per container.no-new-privileges:trueis also set.WorkDir tmpfs overlay: The Docker Compose config creates a tmpfs over
workDirinside the container so the agent cannot readdocker-compose.yml(which contains tokens/API keys in plaintext).Gap โ SYS_ADMIN window (low):
Between container start and the
capsh --dropcall,SYS_ADMINis held with AppArmorunconfined. If entrypoint.sh crashes or is replaced via a bind-mount race, the capability could be misused. The risk is low because the bind mounts are prepared before container start and the entrypoint is fixed in the image.Domain Validation Assessment
Injection prevention (
src/domain-validation.ts):Five-stage validation pipeline:
/[\s\0"'`;#\]/โ prevents Squid config injection via whitespace, comment injection (#`), null bytes, and backslash-regex injection.*,*.*, patterns of only*/.Wildcard-to-regex (
src/domain-patterns.ts):wildcardToRegex()converts*to[a-zA-Z0-9.-]*(explicitly avoiding.*to prevent ReDoS). All regex metacharacters are escaped. The result is anchored:^...$.Gap โ subdomain bypass via trailing label (low/informational):
The plain-domain ACL uses Squid
dstdomain .github.com, which matchesgithub.comand all subdomains. A domain likeevilgithub.comdoes NOT match (Squid'sdstdomainis suffix-matched on label boundaries). This is correct behaviour, but the behaviour depends on Squid's implementation. No code-level vulnerability found.Input Validation Assessment
CLI input (
src/cli-options.ts,src/option-parsers.ts):parseValidPortSpecs()insrc/host-iptables-validation.tsand re-validated withis_valid_port_spec()insetup-iptables.shas defence-in-depth.Shell command construction:
The agent command is passed to
capshvia a shell script file (SCRIPT_FILE=/tmp/awf-cmd-$$.sh, entrypoint.sh line ~1232), not directly interpolated into a shell string. This avoids most shell-injection risks.execausage (src/host-iptables-rules.ts):All
execacalls pass arguments as arrays, not shell strings โ correct practice that prevents shell injection.Secret redaction (
src/redact-secrets.ts):Patterns cover Bearer tokens, GitHub PAT prefixes (
ghp_,gho_,ghu_,ghs_), andTOKEN/SECRET/PASSWORD/KEY/AUTHenv-var patterns. Redaction is applied to logged command strings.srcACL; agent has no NET_ADMINsquid.confbefore Squid reads it--allow-domainsinjects Squid config directivesvalidateDomainOrPattern()insrc/domain-validation.tsblocks all injection chars/etc/resolv.confto use attacker-controlled DNS/etc/resolv.conf; iptables blocks non-whitelisted DNS serversdocker-compose.ymlto extract API keyssrc/services/agent-service.tslines 44โ56)/proc/[pid]/environhidepid=2(entrypoint.sh)X-Forwarded-Forforwarded_for delete; via offin Squid configpids_limit: 1000in agent service configmem_limit: 6g;memswap_limitconfiguredSYS_ADMINafter capsh dropno-new-privileges:true; bounding set cleared by capsh๐ฏ Attack Surface Map
--allow-domainsCLI argvalidateDomainOrPattern()*.example.comin--allow-domains/tmp, workspace bind mounts/etc/shadowexcluded; home dir whitelistAWF_USER_UID/GIDenv varsurl_regexpatterns (opt-in--enable-dlp)๐ Evidence Collection
Network enforcement โ DNAT rules (setup-iptables.sh lines 405โ419)
Domain injection prevention (src/domain-validation.ts)
WorkDir tmpfs overlay (src/services/agent-service.ts lines 44โ56)
Capability management (src/services/agent-service.ts lines 69โ97)
IPv6 disable (setup-iptables.sh ~line 130)
Squid header privacy (src/squid/config-generator.ts lines 148โ149)
โ Recommendations
Medium Priority
Harden AppArmor for entrypoint phase โ Currently
apparmor:unconfinedis required because Docker's default AppArmor profile blocksmount. Consider writing a custom AppArmor profile that allows only the specific mounts performed inentrypoint.sh(procfs at/host/proc) and blocks all other mount targets. This would eliminate the unconfined window whileSYS_ADMINis held.src/services/agent-service.tsline 93Make DLP opt-out rather than opt-in for known high-risk deployments โ The URL-based DLP scanning (
--enable-dlp) for credential patterns (GitHub tokens, OpenAI keys, Anthropic keys) is currently opt-in. For workflows where API proxy credential injection is active (--enable-api-proxy), enabling DLP by default would prevent accidental credential leakage in edge cases where a tool somehow constructs a credential-bearing URL.src/commands/validators/config-assembly.ts(add implication rule)Proxy-unaware HTTPS tools: document failure mode clearly โ The TLS rejection error for proxy-unaware tools is a known, accepted trade-off, but the Squid error response (RST or handshake failure) may be misinterpreted by agents as a transient network error rather than a policy block. Consider adding an explicit
deny_infoSquid directive for HTTPS CONNECT rejections to return a clearer policy message where technically possible, or improve agent-side logging to detect this pattern.Low Priority
Audit
gosuusage alongsidecapshโ entrypoint.sh line ~1355 usesgosu awfuseras an alternative user-switch path. Verify thatgosudoes not re-acquire any capabilities thatcapsh --droppreviously removed.Add explicit
net.ipv4.ip_forwardguard โ The DNAT rules depend on IP forwarding being enabled inside the iptables-init container's network namespace. A startup assertion that verifiesnet.ipv4.ip_forward=1before writing NAT rules would make the failure mode explicit rather than silent.Consider adding an AppArmor profile for Squid container โ The Squid container currently uses
cap_droponly (viaservice-security.ts). An AppArmor profile restricting Squid to only read/etc/squid/,/var/log/squid/, and network operations would add another confinement layer.Verify seccomp profile covers
ptrace,process_vm_readv/writevโ The agent's seccomp profile is incontainers/agent/seccomp-profile.json. Confirm it explicitly deniesptrace,process_vm_readv, andprocess_vm_writevsyscalls, sinceSYS_PTRACEcapability is dropped but the syscall itself is also a vector.Rate-limit review โ If
--rate-limitis implemented, ensure the rate-limit state is stored in a file system path that is also covered by the workDir tmpfs overlay, preventing the agent from reading timing state.๐ 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