[Security Review] Daily Security Review and Threat Modeling — 2026-03-29 #1491
Closed
Replies: 1 comment
-
|
This discussion was automatically closed because it expired on 2026-04-05T13:48:07.318Z.
|
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
📊 Executive Summary
This security review analyzed 6,506 lines of security-critical code across the AWF codebase, covering the full defense-in-depth stack: host-level iptables, container-level iptables, Squid proxy, Docker compose hardening, capability management, seccomp profile, the one-shot token library, and the API proxy sidecar.
Overall assessment: Secure architecture with strong defense-in-depth. No critical firewall bypass vulnerabilities were found. The system correctly layers multiple enforcement mechanisms. Several lower-severity hardening opportunities and two outdated dependencies (including one with known critical CVEs) are documented below.
mount/unshare(capabilities compensate)unconfined) to allow procfs mountcapsh+gosu/chroot+no-new-privilegesunset_sensitive_tokens()handlebars@4.7.8(critical, devDeps);brace-expansion(moderate)🔍 Findings from Previous Security Test Runs
The
agenticworkflows-logstool was unable to retrieve prior firewall-escape-test run logs due to agitbinary path issue in the sandbox environment. This review is therefore based entirely on static analysis of the current codebase.🛡️ Architecture Security Analysis
Network Security — Two-Layer Enforcement
AWF implements a two-layer network enforcement model:
Layer 1 — Host-level (
src/host-iptables.ts)The
FW_WRAPPERiptables chain is inserted intoDOCKER-USERand applies to all egress from the container bridge. Evidence:This catch-all REJECT blocks all traffic not explicitly allowed, including ICMP. UDP is explicitly blocked at line 515–519. Multicast and link-local (
169.254.0.0/16,224.0.0.0/4) are rejected at lines 488–505.Layer 2 — Container-level (
containers/agent/setup-iptables.sh)Inside the agent container, NAT rules redirect HTTP/HTTPS to Squid, and OUTPUT filter rules enforce a default-deny on TCP and UDP:
# setup-iptables.sh:405,407 iptables -A OUTPUT -p tcp -j DROP iptables -A OUTPUT -p udp -j DROPThe container-level OUTPUT chain only drops TCP and UDP — ICMP is never addressed. While host-level rules REJECT ICMP at the Docker bridge, a misconfigured or single-layer deployment (container without host rules) would leave ICMP unfiltered. Modern kernels allow unprivileged ICMP echo via ping sockets (without
NET_RAW), so even withNET_RAWdropped, ping may work within the container.The
NET_RAWcapability is correctly dropped in docker-manager.ts line 1159, blocking raw socket ICMP. However, defense-in-depth recommends an explicit container-level drop.Container Security Hardening
Capability management is well-implemented:
SYS_ADMIN(required for procfs mount) andSYS_CHROOTare granted to the container but dropped before user code runs via capsh in chroot mode (always enabled):The
AWF_CHROOT_ENABLED=trueis hardcoded insrc/docker-manager.ts:707, ensuring the capability drop always fires.no-new-privileges:trueis set at line 1170, preventing privilege escalation via setuid binaries.unconfinedAppArmor is disabled because Docker's default profile blocks the
mount()syscall needed for procfs. This is a documented trade-off, but it removes an important MAC layer. If Docker's AppArmor profile could be customized (allow only the specificmounttarget needed), the container could run with AppArmor protection.Seccomp Profile Assessment
The seccomp profile (
containers/agent/seccomp-profile.json) usesSCMP_ACT_ERRNOas the default action — correctly deny-by-default. However, the broad allow list includes sensitive syscalls:# Sensitive syscalls allowed in seccomp: mount, unshare, clone, clone3, setuid, setgid, capset, prctlmountandunshareallowed in seccompWithout
SYS_ADMIN(dropped by capsh),mount()with filesystem types andunshare -m(new mount namespace) will fail with EPERM at the kernel level. However,unshare --user(user namespace creation) may succeed on Ubuntu 22.04 kernels ifunprivileged_userns_clone=1. Creating a user namespace could allow privilege mapping that re-grants some capabilities within that namespace. This should be evaluated against the host kernel's sysctl settings.The explicit
ptrace,process_vm_readv,process_vm_writevblock is a good addition:{ "names": ["ptrace", "process_vm_readv", "process_vm_writev"], "action": "SCMP_ACT_ERRNO", "errnoRet": 1 }Domain Validation Assessment
Domain validation in
src/domain-patterns.tsis robust:[a-zA-Z0-9.-]*(character class, not.*) — line 77*,*.*, patterns with >50% wildcard segments — lines 155–197^...$anchoring prevents partial matches — line 130The Squid config also blocks raw IPv4/IPv6 connections:
This prevents agents from bypassing domain filtering by connecting to raw IP addresses.
Input Validation — Command Injection Assessment
The CLI uses
commanderfor argument parsing. All Docker/Squid commands are executed viaexecawith argument arrays (not shell strings), which prevents shell injection:The entrypoint script writes user commands to a temporary script file. The key section that writes the command uses
printf '%s\n' "$3"(not eval), and requires exactly 3 arguments to avoid shell injection:The trust comment is explicit: "Trust assumption: $3 comes from Docker CMD set by docker-manager.ts using the user's own --allow-domains command."
Token Protection Assessment
The one-shot-token library (
containers/agent/one-shot-token/one-shot-token.c) interceptsgetenv()calls, caches the value in memory, and callsunsetenv()on first access. Token names are XOR-obfuscated with key0x5Ato prevent discovery viastrings.The entrypoint runs the agent in the background and unsets tokens after 5 seconds:
mountandunshareare allowed butSYS_ADMINis dropped before user code, making exploitation infeasible in practice.Command: iptables OUTPUT chain analysis (setup-iptables.sh)
Command: capability inspection (docker-manager.ts:1156-1164)
✅ Recommendations
🔴 High — Fix Now
H-1: Update vulnerable devDependencies
cd /home/runner/work/gh-aw-firewall/gh-aw-firewall npm audit fixhandlebars@4.7.8has 6 known CVEs (JavaScript injection, prototype pollution, DoS). While currently devDependencies only, these could be exploited in CI build pipelines ifnpm installruns in a context where attacker-controlled templates are processed. Update to latest.🟡 Medium — Fix Soon
M-1: Add explicit ICMP DROP at container level (
setup-iptables.sh)The container OUTPUT chain drops TCP and UDP but not ICMP. While the host-level
FW_WRAPPERcatch-all REJECT handles this, defense-in-depth recommends an explicit container-level block. Add before the TCP/UDP DROP rules:This is a higher-effort change but closes a meaningful isolation gap.
🟢 Low — Plan to Address
L-1: Evaluate blocking
unsharewithCLONE_NEWUSERflag in seccompIf the host kernel has
unprivileged_userns_clone=1, an unprivileged agent could create user namespaces to re-map capabilities. Consider adding a seccomp rule to blockunsharewith theCLONE_NEWUSERflag:{ "names": ["unshare"], "action": "SCMP_ACT_ERRNO", "args": [{"index": 0, "value": 268435456, "op": "SCMP_CMP_MASKED_EQ", "valueTwo": 268435456}] }Or verify the host kernel has
kernel.unprivileged_userns_clone=0.L-2: JSON-escape URL field in JSONL audit log
From
src/squid-config.ts, the JSONL log format comment notes: "Squid logformat does not JSON-escape strings, so fields like User-Agent could break JSON parsing." Theurlfield (%ru) is still present in the JSONL format and can contain unescaped double-quotes or backslashes from agent-generated URLs, breaking audit log parsing. Consider switching toaccess_log_json_output on(Squid 5+) or post-processing logs.L-3: Reduce the 5-second token inheritance window
The
sleep 5inentrypoint.shbefore callingunset_sensitive_tokens()is a fixed window during which sub-processes inherit tokens. Consider reducing to 1 second, or using a process-readiness signal (e.g., wait for a specific log line or file) rather than a fixed delay. The one-shot-token library helps, but sub-processes that don't callgetenv()bypass it.📈 Security Metrics
Review conducted: 2026-03-29. Methodology: static analysis of codebase at current HEAD. No live container testing was performed.
Beta Was this translation helpful? Give feedback.
All reactions