[Security Review] Daily Security Review — 2026-03-11 #1226
Closed
Replies: 1 comment
-
|
This discussion was automatically closed because it expired on 2026-03-18T13:56:52.662Z.
|
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 covers the gh-aw-firewall codebase as of 2026-03-11. The overall security posture is strong, with layered defenses (host-level iptables, container-level iptables, Squid proxy ACLs, capability dropping, seccomp, and credential file hiding). No critical or high-severity vulnerabilities were found. npm audit reports 0 known vulnerabilities in dependencies. Four medium-severity findings and two low-severity findings are identified below.
🔍 Phase 1: Escape Test Agent Context
No
firewall-escape-testworkflow was found viaagenticworkflows-status. This section is therefore based entirely on direct code analysis in Phases 2–5.🛡️ Phase 2: Architecture Security Analysis
2.1 Network Security Architecture
Two-layer enforcement:
Host layer (
src/host-iptables.ts): Creates a dedicatedFW_WRAPPERchain inDOCKER-USER, enforcing allowlist via REJECT on exit from the bridge interface. Blocks multicast (ADDRTYPE MULTICAST), link-local (169.254.0.0/16), multicast (224.0.0.0/4), all UDP except whitelisted DNS servers, and then all other traffic with a defaultREJECT.Container layer (
containers/agent/setup-iptables.sh): NAT-based DNAT redirects HTTP/HTTPS through Squid; dangerous ports (22, 25, 445, 3306, 5432, 6379, 27017, etc.) are sent through theRETURNpath and hit the OUTPUT filter chainDROP. Final rule:iptables -A OUTPUT -p tcp -j DROP.Cloud metadata endpoint blocked:
DNS exfiltration prevention:
8.8.8.8,8.8.4.4) receive DNS traffic. Custom DNS servers validated viaparseDnsServers()againstisValidIPv4/isValidIPv6.AWF_DNS_SERVERSenvironment variable is validated at CLI entry before being passed to the container.IPv6 handling:
ip6tablesis unavailable, IPv6 is disabled viasysctl net.ipv6.conf.all.disable_ipv6=1— preventing an unfiltered bypass path. ✅Rule ordering:
src/squid-config.ts:388). ✅2.2 Container Security Hardening
Capabilities
Agent container (
src/docker-manager.ts:896):All three added capabilities are dropped via
capshbefore user commands execute:no-new-privileges:trueis set, preventing privilege escalation after capsh runs. ✅The API proxy sidecar drops ALL capabilities (
cap_drop: ['ALL']). ✅Seccomp Profile —⚠️ FINDING M-1
Evidence (
containers/agent/seccomp-profile.json):{ "defaultAction": "SCMP_ACT_ALLOW", "syscalls": [ { "action": "SCMP_ACT_ERRNO", "names": ["ptrace", "process_vm_readv", "process_vm_writev"] }, { "action": "SCMP_ACT_ERRNO", "names": ["kexec_load", "kexec_file_load", "reboot", "init_module", ...] }, { "action": "SCMP_ACT_ERRNO", "names": ["umount", "umount2"] } ] }Assessment: The default action is
SCMP_ACT_ALLOW, meaning all syscalls NOT explicitly listed are permitted. Docker's built-in default seccomp profile also usesSCMP_ACT_ALLOWbut maintains a much more comprehensive blocklist (~44 syscalls). This custom profile only explicitly blocks 28 syscalls total.Risk: Capability drops provide good defense-in-depth here, but an allow-by-default seccomp profile with a sparse blocklist provides weaker isolation than Docker's default. Notably, syscalls like
socket(AF_NETLINK),clone3, and various namespace-related calls are not explicitly blocked.Severity: Medium
AppArmor Unconfined —⚠️ FINDING M-2
Evidence (
src/docker-manager.ts:912):Assessment: AppArmor is disabled to allow mounting procfs at
/host/procin chroot mode. WhileSYS_ADMINis dropped before user code runs (making unauthorized mounts impossible), the absence of AppArmor removes MAC-layer protections that would otherwise restrict file access patterns, network operations, and capability usage at the OS level.Note: This trade-off is documented and intentional (comment at line 907).
Severity: Medium
2.3 Domain Pattern Validation
ReDoS protection: Wildcards are converted to
[a-zA-Z0-9.-]*(not.*), preventing catastrophic backtracking. ✅Overly broad patterns blocked:
*,*.*, and purely wildcard patterns are rejected. ✅Subdomain matching:
github.com→.github.comin Squid (matches parent + subdomains). ✅Domain Config Injection —⚠️ FINDING M-3
Evidence (
src/domain-patterns.ts—validateDomainOrPatternfunction):The
validateDomainOrPatternfunction does not check for embedded newline or carriage-return characters. If a domain string contains a literal\n, the resultingsquid.confline would be split across two lines, potentially injecting arbitrary Squid directives.Affected paths:
--allow-domainsCLI flag (requires shell$'...'quoting or environment variable expansion)--allow-domains-file(if a single comma-separated entry within a line contains\n)parseDomainsFile(src/cli.ts:46) splits on\nfirst, so file-based injection via line separators is already mitigated. The risk applies only to domains passed via the CLI flag with embedded literal newlines or programmatic API usage.Example PoC (self-exploitation):
Severity: Medium (requires attacker to control the domain argument; typically self-exploitation)
2.4 SSH Directory Coverage Gap —⚠️ FINDING M-4
Evidence (
src/docker-manager.ts:787-803):Hidden SSH private keys:
~/.ssh/id_rsa✅~/.ssh/id_ed25519✅~/.ssh/id_ecdsa✅~/.ssh/id_dsa✅NOT hidden:
~/.ssh/config— may reveal hostnames, jump hosts, and SSH server configuration~/.ssh/known_hosts— reveals SSH server fingerprints and internal hostnames~/.ssh/authorized_keys— reveals which public keys have access~/.ssh/id_ecdsa_sk/~/.ssh/id_ed25519_sk— FIDO hardware-backed keys (less critical but still private keys)While these files cannot be used for direct authentication without the corresponding private key (which IS hidden),
~/.ssh/configandknown_hostscan leak internal infrastructure topology.Severity: Medium
2.5 Input Validation Assessment
Shell argument escaping (
src/cli.ts:504):Proper single-quote escaping prevents command injection when multi-word arguments are joined. ✅
Docker Compose
$escaping (src/docker-manager.ts:922):Prevents Docker Compose variable interpolation from consuming shell variables in user commands. ✅
execausage: All external commands use array argument form (not shell interpolation), preventing command injection through arguments. ✅2.6 Container-Level ICMP Handling —⚠️ FINDING L-1
Evidence (
containers/agent/setup-iptables.sh:295):Command: domain newline injection test
✅ Recommendations
🔴 Critical
None identified.
🟠 High
None identified.
🟡 Medium
[M-1] Harden seccomp profile to blocklist more syscalls
containers/agent/seccomp-profile.json[M-2] Re-evaluate AppArmor:unconfined scope
src/docker-manager.ts:912[M-3] Add newline/control-character validation in domain parsing
\n,\r) and other control characters invalidateDomainOrPattern(). This prevents Squid configuration injection if domains are sourced from untrusted automated inputs.src/domain-patterns.ts— add tovalidateDomainOrPattern():[M-4] Extend SSH directory credential hiding
~/.ssh/configand~/.ssh/known_hoststo the credential file hiding list to prevent leakage of internal SSH topology.~/.ssh/id_ecdsa_skand~/.ssh/id_ed25519_skfor completeness.src/docker-manager.ts:787-803(credentialFiles array)🟢 Low
[L-1] Add explicit ICMP DROP in container OUTPUT chain
iptables -A OUTPUT -p icmp -j DROPtosetup-iptables.shbefore the final TCP DROP rule to prevent ICMP to container-local addresses.containers/agent/setup-iptables.sh[L-2] Document the SYS_ADMIN startup window
📈 Security Metrics
Beta Was this translation helpful? Give feedback.
All reactions