[Security Review] Daily Security Review — AWF Firewall Codebase (2026-04-15) #1988
Replies: 3 comments
-
|
🔮 The ancient spirits stir in the firewall winds.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir, and the oracle marks this hall.
|
Beta Was this translation helpful? Give feedback.
-
|
🔮 The ancient spirits stir in the wires.
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
📊 Executive Summary
Review date: 2026-04-15
Scope: Full codebase — network layer, container security, domain validation, input sanitization, dependency chain
Overall posture: Good — the system is thoughtfully engineered with multiple defense layers. No critical vulnerabilities were found. Several medium-severity gaps are documented below.
assertSafeForSquidConfig, regex anchoring--allow-dockeropt-in grants full host escapenpm auditreports 0 vulns (26 prod deps)🔍 Findings from Firewall Escape Test Context
The pre-fetched file at
/tmp/gh-aw/escape-test-summary.txtcontained GitHub Actions runner logs for the Secret Digger (Copilot) workflow (run24273493151). The workflow concluded with:This indicates: the secret-digger agent ran, verified the firewall successfully blocked secret exfiltration attempts, and published a noop (no secrets were discoverable). This is the expected passing result — the firewall held.
🛡️ Architecture Security Analysis
Network Security Assessment
Host layer (
src/host-iptables.ts)AWF installs a custom
FW_WRAPPERchain inDOCKER-USER— the correct hook for egress filtering before Docker's own masquerade rules:The default deny is a REJECT (not DROP), which is appropriate — DROP can cause long timeouts that leak timing information, while REJECT with ICMP-port-unreachable gives fast feedback without permitting traffic.
IPv6 handling is well-implemented: if
ip6tablesis unavailable, the host falls back to disabling IPv6 viasysctl(src/host-iptables.ts:132-143), eliminating the bypass path.Container layer (
containers/agent/setup-iptables.sh)The iptables-init init container (network_mode: service:agent) correctly separates
NET_ADMINfrom the agent — a significant improvement over the naive approach of grantingNET_ADMINto the agent itself.The OUTPUT chain default-deny covers TCP and UDP only:
# setup-iptables.sh:427-430 iptables -A OUTPUT -p tcp -j DROP iptables -A OUTPUT -p udp -j DROPREJECTmay stop Internet-bound ICMP depending on bridge routing, but intra-subnet ICMP on172.30.0.0/24(e.g., ping to gateway172.30.0.1) is definitely reachable. Evidence:Dangerous port blocking covers 15 well-chosen ports (22, 23, 25, 110, 143, 445, 1433, 1521, 3306, 3389, 5432, 6379, 27017-18, 28017). However, many other high-risk ports (e.g., 8443, 9200 Elasticsearch, 11211 Memcached, 5900 VNC) are not blocked. These only matter if the agent somehow reaches internal infrastructure — the primary domain ACL at Squid is the relevant control.
Container Security Assessment
Capabilities:
SYS_CHROOTandSYS_ADMINare added at container start but dropped viacapshbefore user code runs (containers/agent/entrypoint.sh:357, 824). This is a time-of-use window — the entrypoint holds elevated capabilities during setup. This is mitigated byno-new-privileges:truepreventing privilege re-acquisition after the drop.The iptables init container drops all capabilities except
NET_ADMINandNET_RAW:This is correct isolation.
Seccomp profile:
# containers/agent/seccomp-profile.json Total allowed syscalls: 371Several high-risk syscalls are allowed in the seccomp profile:
mountunshareprocess_vm_readv/process_vm_writevkeyctl/add_key/request_keykcmpio_uring_*syslogptraceis correctly blocked (SCMP_ACT_ERRNO), preventing process injection/tracing.no-new-privileges is set for all service containers:
Docker socket access (
--allow-dockerflag):When
--allow-dockeris passed, the Docker socket is bind-mounted into the agent chroot read-write. Access to/var/run/docker.sockis equivalent to root on the host — an agent can start privileged containers, mount host filesystems, etc. This is flagged as a design-level risk that users must understand when choosing to enable this flag. The documentation should include an explicit security warning.Volume mount exposure:
Host directories
~/.config,~/.cache,~/.localare mounted read-write into the agent:~/.config/gh/hosts.yml(GitHub CLI authentication),~/.config/gcloud/credentials.db, npm tokens, and other credentials stored here are accessible to the agent. This is an intentional trade-off for usability (agents need git/gh credentials) but is worth noting.Domain Validation Assessment
The domain sanitization code in
src/domain-patterns.tsis solid:assertSafeForSquidConfig()is applied to both domain names and URL patterns before they entersquid.conf. The wildcard-to-regex conversion anchors patterns (^.*\.github\.com$) and uses a restricted character class[a-zA-Z0-9.-]*to prevent ReDoS.One edge case: the
$character is not inSQUID_DANGEROUS_CHARS. In Squid config,$is not a shell expansion character, but it's worth verifying Squid does not interpret it in any ACL context. Likely safe, but worth a unit test.Input Validation Assessment
Shell injection in Docker Compose
command:The
$$replacement escapes YAML/docker-compose variable interpolation. TheagentCommandstring is passed through bash-c, which means shell metacharacters in the user command (;,|,&&,$(...), backticks) are interpreted. This is intentional by design — users pass shell commands. The agent container's iptables/domain controls are the containment boundary, not shell escaping.UID/GID injection via
AWF_USER_UID:Strong validation prevents UID 0 (root) or non-numeric values. Good.
Maven/Gradle config injection (
entrypoint.sh:283-311):The
$PROXY_HOSTand$PROXY_PORTvariables are interpolated intosettings.xmlandgradle.propertiesvia heredoc. The proxy host is parsed fromHTTP_PROXYenv var. SinceHTTP_PROXYis always set by AWF to the Squid container IP (172.30.0.10), this is not exploitable externally. But if theSQUID_PROXY_HOST/HTTP_PROXYwere somehow overridden, XML injection intosettings.xmlwould be possible.io_uringkernel exploit (CVE-based)process_vm_readvsidecar memory leak--allow-docker~/.config/~/.cachecredential harvesting*)unsharenamespace manipulation/tmp/awf-init/ready)$in domain~/.config/gh🎯 Attack Surface Map
src/squid-config.tscontainers/agent/setup-iptables.sh:341containers/agent/setup-iptables.shsetup-iptables.sh:154-162src/docker-manager.ts:1110-1213~/.config,~/.cacherwsrc/docker-manager.ts:1305/var/run/docker.sockrw--allow-dockercontainers/squid/Dockerfilecontainers/agent/seccomp-profile.jsonio_uring,mount,unsharepresentsrc/docker-manager.ts:1568containers/agent/seccomp-profile.jsonprocess_vm_readv📋 Evidence Collection
Network rules — ICMP gap confirmation
Seccomp dangerous syscalls
Docker socket conditional mount
Domain validation
One-shot token protection
The
containers/agent/one-shot-token/LD_PRELOAD library:getenv()for sensitive vars (GITHUB_TOKEN, ANTHROPIC_API_KEY, etc.)environon first read; caches value in heap memory.rodatato resiststringsextractionpthread_mutex_tAWF_ONE_SHOT_TOKENS✅ Recommendations
🔴 High
H1 — Block ICMP outbound in agent container OUTPUT chain
🟡 Medium
M1 — Tighten seccomp: consider blocking
process_vm_readv/process_vm_writevThese syscalls allow one process to read/write another's memory without ptrace. In a container they are constrained by PID namespace, but blocking them reduces the attack surface if an agent tries to extract data from a co-located sidecar process.
M2 — Consider blocking
io_uring_*syscallsio_uringhas been the source of multiple kernel privilege escalation CVEs (CVE-2022-29582, CVE-2023-2598, etc.). Unless the agent workloads specifically require it, addingio_uring_setup,io_uring_enter,io_uring_registerto the ERRNO list reduces kernel attack surface.M3 — Add
$to Squid config dangerous character validationAdd a unit test confirming that a domain containing
$(e.g.,$$injected) does not produce unexpected Squid config behavior. While Squid config does not perform shell expansion, confirm withassertSafeForSquidConfigcoverage.M4 — Document
~/.config/~/.cacheRW credential exposureAdd a section to
docs/environment.mdexplaining that~/.config/gh/hosts.yml,~/.npmrc,~/.config/gcloud/credentials.dband similar files are accessible to the agent via the RW home directory mounts. Users should understand this when using AWF with credentials-bearing home directories.M5 — DLP extension: request body scanning
The current DLP implementation (
src/dlp.ts) only scans URLs for credential patterns. Consider enabling Squid'surl_rewrite_programoradaptation_serviceto scan POST body content for high-value patterns (GitHub tokens, API keys) when SSL Bump is enabled.🟢 Low
L1 — Add
unshareto the seccomp ERRNO list (low priority given SYS_ADMIN dropped before user code)L2 — Add ICMP to the dangerous port logging audit trail — if H1 is implemented, ensure ICMP blocks are logged to the audit dump at
/tmp/awf-init/iptables-audit.txt.L3 — Consider
syslogsyscall block —syslog(2)allows reading the kernel ring buffer. Low sensitivity in containers, but noisy for security auditors.📈 Security Metrics
Beta Was this translation helpful? Give feedback.
All reactions