You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The gh-aw-firewall codebase demonstrates a mature, defense-in-depth security posture with multiple overlapping control layers: iptables NAT/filter chains, Squid L7 domain ACLs, capability drops, seccomp (deny-by-default), DLP scanning, workdir tmpfs overlays, and /proc credential isolation. No 0-day vulnerabilities or critical injection flaws were found. npm audit returns zero CVEs. The primary residual risks are architectural trade-offs (AppArmor disabled for mount support, DinD socket exposure) rather than implementation bugs.
Key Metrics:
3,674 lines of security-critical code analyzed across 13 files
0 npm dependency CVEs
7 attack surfaces mapped
20+ dangerous ports blocked at both NAT and filter layers
Seccomp profile: deny-by-default (SCMP_ACT_ERRNO)
π Findings from Firewall Escape Test
The pre-fetched escape test summary (/tmp/gh-aw/escape-test-summary.txt) was empty β no escape test results were available for this review cycle. The analysis below is based entirely on static code analysis and evidence gathered from the live repository.
π‘οΈ Architecture Security Analysis
Network Security Assessment
Two-layer enforcement model (containers/agent/setup-iptables.sh, src/host-iptables-rules.ts):
if(!ip6tablesAvailable){logger.warn('ip6tables not available, disabling IPv6 via sysctl to prevent unfiltered bypass');awaitdisableIpv6ViaSysctl();}
Fail-secure: if ip6tables is absent, IPv6 is disabled at sysctl level.
HTTP proxy visibility gap (documented design choice in containers/agent/ README): http_proxy (lowercase) is intentionally not set. On Ubuntu 22.04, curl ignores uppercase HTTP_PROXY for HTTP (httpoxy mitigation), so HTTP falls through to iptables DNAT β Squid. This is by design and works correctly, but proxy-unaware tools making HTTP requests may produce non-obvious errors for operators debugging blocked requests.
Container Security Assessment
Capability model (src/services/agent-service.ts:77β93):
Capability
Agent
iptables-init
API Proxy
Notes
NET_ADMIN
β never granted
β required
β
Init container only, dropped after use
SYS_CHROOT
β β dropped
β
β
Dropped via capsh before user code
SYS_ADMIN
β β dropped
β
β
Dropped via capsh before user code
NET_RAW
β dropped
β
β
Blocks raw socket iptables bypass
SYS_PTRACE
β dropped
β
β
Blocks process inspection
ALL others (sidecars)
β
β
cap_drop: ALL
Full drop for proxy sidecars
Evidence β capsh drop (containers/agent/entrypoint.sh:401β404):
if [ "${AWF_CHROOT_ENABLED}"="true" ];then
CAPS_TO_DROP="cap_sys_chroot,cap_sys_admin"
AWF_CHROOT_ENABLED=true is always set (src/services/agent-environment/api-proxy-environment.ts:42), so caps are always dropped.
Seccomp profile (containers/agent/seccomp-profile.json): defaultAction: SCMP_ACT_ERRNO β deny-by-default with explicit syscall allowlist. Confirmed by test: seccomp-profile.test.ts.
Docker's default AppArmor profile blocks mount(2). AWF needs SYS_ADMIN + mount to establish procfs at /host/proc with hidepid=2. AppArmor is set to unconfined to permit this. Mitigated: SYS_ADMIN is dropped via capsh before user code runs, so user code cannot remount. Seccomp profile provides the remaining syscall guard.
workDir tmpfs overlay (src/services/agent-service.ts:46β55) β prevents agent from reading docker-compose.yml (which contains API tokens as env vars):
/proc credential isolation (containers/agent/entrypoint.sh:509β520):
Procfs mounted with hidepid=2 at /host/proc. unset_sensitive_tokens() clears 16 credential env vars before exec. The run_agent_with_token_protection function launches the agent in background, unsets tokens, then waits β closing the /proc/1/environ race window.
Domain names additionally reject backslash (/[\s\0"';#\]/) to block regex injection. URL patterns (for --allow-urls`) allow backslash intentionally for regex escaping.
ReDoS prevention (src/domain-patterns.ts:66):
constDOMAIN_CHAR_PATTERN='[a-zA-Z0-9.-]*';// NOT .*
Wildcard * is converted to a character class, not .*, preventing catastrophic backtracking in Squid's regex engine.
Over-broad pattern rejection (src/domain-validation.ts:49β62): *, *.*, and any pattern of only */. are rejected. Patterns with too many wildcard segments (β₯ totalSegments-1) also rejected.
Input Validation Assessment
--allow-host-ports: Validated twice β in TypeScript (parseValidPortSpecs) and in shell (split_valid_port_specs in setup-iptables.sh). Dangerous ports blocked even with explicit user request (src/squid/validation.ts:validateAndSanitizeHostAccessPort).
--agent-image: Restricted to approved patterns only (src/domain-utils.ts:SAFE_BASE_IMAGE_PATTERNS) β official Ubuntu, catthehacker runner images, or SHA256-pinned. Prevents supply chain attacks via custom base images without --build-local.
Port specification leading-zero rejection (setup-iptables.sh:27): Rejects 080 to prevent octal interpretation, aligned with TypeScript isValidPortSpec().
β οΈ Threat Model
#
Threat (STRIDE)
Location
Likelihood
Impact
Severity
Mitigation
T1
EoP: Agent retains SYS_ADMIN window between container start and capsh drop
entrypoint.sh, ~startup seconds
Low
High
Medium
Window is seconds only; no user code runs before drop; workdir tmpfs hides secrets
T2
EoP/ID: AppArmor unconfined allows agent to use mount(2) before capsh drop
agent-service.ts:93
Low
High
Medium
Seccomp profile + SYS_ADMIN drop before user code mitigates
T3
DoS: Squid regex engine via crafted --allow-urls patterns
domain-matchers.ts:parseUrlPatterns
Medium
Medium
Medium
User controls their own firewall config; character class wildcards prevent most ReDoS
T4
ID: DinD socket exposure (--enable-dind) grants full container escape
src/dind-bootstrap.ts
Low (opt-in)
Critical
High
Optional feature; documented risk; operator must explicitly opt in
T5
Bypass: AWF_ALLOW_HOST_PORTS env var fallback without strict validation if container/CLI version mismatch
src/services/agent-environment/api-proxy-environment.ts:42: environment.AWF_CHROOT_ENABLED = 'true'; // always set
containers/agent/entrypoint.sh:402: CAPS_TO_DROP="cap_sys_chroot,cap_sys_admin"
containers/agent/entrypoint.sh:408: CAPS_TO_DROP="" # only if AWF_CHROOT_ENABLED != true (never in practice)
H1 β Document and gate DinD socket exposure risk (src/dind-bootstrap.ts, CLI --enable-dind)
The Docker socket bind-mount is a full container escape vector. Consider adding a mandatory acknowledgment flag (e.g., --enable-dind-i-understand-the-risk) or a prominent runtime warning when --enable-dind is used in non-CI contexts. Current documentation notes the risk but there is no runtime friction.
H2 β Harden dangerous-port list: add Docker API and common dev-server ports
Port 2375 (Docker API unencrypted), 2376 (Docker API TLS), 8080, 8443, 9090 (Prometheus), 4040 are absent from DANGEROUS_PORTS. An agent aware of the host network could reach these services via --enable-host-access. File:src/squid/policy-manifest.ts
π‘ Medium Priority
M1 β AppArmor custom profile instead of unconfined (src/services/agent-service.ts:93)
Currently apparmor:unconfined disables Docker's AppArmor guard. A narrow custom AppArmor profile that allows only the specific mount call needed for procfs (type proc, flags hidepid=2) would restore AppArmor as a defense-in-depth layer without blocking SYS_ADMIN+mount. This is non-trivial but would eliminate the AppArmor coverage gap.
M2 β SYS_ADMIN window explicit test (entrypoint.sh)
Add an integration test that verifies SYS_ADMIN is absent from /proc/self/status capabilities after the agent process starts. This guards against regressions where capsh is skipped (e.g., AWF_CHROOT_ENABLED not being set).
M3 β Rate-limit tuning for LOG rules (setup-iptables.sh:477)
The LOG rules use --limit 5/min --limit-burst 10. A short burst attack (e.g., 100 connection attempts in 1 second) would only log the first 10, leaving 90 attempts invisible in audit logs. Consider raising burst to 50 or adding per-IP rate limiting with --hashlimit.
M4 β SSL Bump CA key fallback logging (src/ssl-bump.ts)
When tmpfs mount fails (common in non-root environments), the CA key falls back to disk with only a logger.debug message. Raise to logger.warn to ensure operators are notified that key material is on disk.
π’ Low Priority
L1 β --allow-urls regex complexity limit
User-supplied URL patterns accepted by --allow-urls could include high-complexity regexes that stress Squid's POSIX regex engine. Add a maximum length check (e.g., 500 chars) and reject patterns containing recursive constructs ((?:...), lookahead, etc.) that are not needed for URL matching.
L2 β AWF_ALLOW_HOST_PORTS fallback removal setup-iptables.sh:409 falls back to unvalidated AWF_ALLOW_HOST_PORTS if AWF_VALID_ALLOW_HOST_PORTS is absent (version mismatch scenario). Consider emitting a clear error and aborting rather than processing potentially unvalidated port specs.
L3 β HTTP traffic operator visibility
The intentional omission of http_proxy (httpoxy mitigation) means HTTP-blocked requests produce a different error UX than HTTPS-blocked requests. Add a startup log message explaining this so operators don't misdiagnose HTTP blocks as infrastructure failures.
π Security Metrics
Metric
Value
Security-critical source files analyzed
13
Total lines analyzed
3,674
npm dependency CVEs
0
Attack surfaces mapped
9
STRIDE threats identified
10
Critical findings
0
High findings
2
Medium findings
4
Low findings
3
Defense layers (network)
2 (iptables + Squid)
Defense layers (container)
4 (caps + seccomp + tmpfs + procfs hidepid)
Dangerous ports blocked
21
Warning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
awmgmcpg
To allow these domains, add them to the network.allowed list in your workflow frontmatter:
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
π Executive Summary
The
gh-aw-firewallcodebase demonstrates a mature, defense-in-depth security posture with multiple overlapping control layers: iptables NAT/filter chains, Squid L7 domain ACLs, capability drops, seccomp (deny-by-default), DLP scanning, workdir tmpfs overlays, and/proccredential isolation. No 0-day vulnerabilities or critical injection flaws were found.npm auditreturns zero CVEs. The primary residual risks are architectural trade-offs (AppArmor disabled for mount support, DinD socket exposure) rather than implementation bugs.Key Metrics:
SCMP_ACT_ERRNO)π Findings from Firewall Escape Test
The pre-fetched escape test summary (
/tmp/gh-aw/escape-test-summary.txt) was empty β no escape test results were available for this review cycle. The analysis below is based entirely on static code analysis and evidence gathered from the live repository.π‘οΈ Architecture Security Analysis
Network Security Assessment
Two-layer enforcement model (
containers/agent/setup-iptables.sh,src/host-iptables-rules.ts):Evidence β default-deny filter chain (
setup-iptables.sh:482β498):Evidence β dangerous port NAT blacklist (
src/squid/policy-manifest.ts):IPv6 bypass mitigation (
src/host-iptables-rules.ts:89β91):Fail-secure: if
ip6tablesis absent, IPv6 is disabled at sysctl level.HTTP proxy visibility gap (documented design choice in
containers/agent/README):http_proxy(lowercase) is intentionally not set. On Ubuntu 22.04,curlignores uppercaseHTTP_PROXYfor HTTP (httpoxy mitigation), so HTTP falls through to iptables DNAT β Squid. This is by design and works correctly, but proxy-unaware tools making HTTP requests may produce non-obvious errors for operators debugging blocked requests.Container Security Assessment
Capability model (
src/services/agent-service.ts:77β93):cap_drop: ALLEvidence β capsh drop (
containers/agent/entrypoint.sh:401β404):AWF_CHROOT_ENABLED=trueis always set (src/services/agent-environment/api-proxy-environment.ts:42), so caps are always dropped.Seccomp profile (
containers/agent/seccomp-profile.json):defaultAction: SCMP_ACT_ERRNOβ deny-by-default with explicit syscall allowlist. Confirmed by test:seccomp-profile.test.ts.AppArmor unconfined (
src/services/agent-service.ts:93):Docker's default AppArmor profile blocks
mount(2). AWF needsSYS_ADMIN+ mount to establish procfs at/host/procwithhidepid=2. AppArmor is set tounconfinedto permit this. Mitigated: SYS_ADMIN is dropped via capsh before user code runs, so user code cannot remount. Seccomp profile provides the remaining syscall guard.workDir tmpfs overlay (
src/services/agent-service.ts:46β55) β prevents agent from readingdocker-compose.yml(which contains API tokens as env vars):/proccredential isolation (containers/agent/entrypoint.sh:509β520):Procfs mounted with
hidepid=2at/host/proc.unset_sensitive_tokens()clears 16 credential env vars before exec. Therun_agent_with_token_protectionfunction launches the agent in background, unsets tokens, then waits β closing the/proc/1/environrace window.Domain Validation Assessment
Squid injection prevention (
src/domain-validation.ts:23):Blocks whitespace (line injection), null bytes, quotes, semicolons, backticks, hash (comment injection).
Domain names additionally reject backslash (
/[\s\0"';#\]/) to block regex injection. URL patterns (for--allow-urls`) allow backslash intentionally for regex escaping.ReDoS prevention (
src/domain-patterns.ts:66):Wildcard
*is converted to a character class, not.*, preventing catastrophic backtracking in Squid's regex engine.Over-broad pattern rejection (
src/domain-validation.ts:49β62):*,*.*, and any pattern of only*/.are rejected. Patterns with too many wildcard segments (β₯ totalSegments-1) also rejected.Input Validation Assessment
--allow-host-ports: Validated twice β in TypeScript (parseValidPortSpecs) and in shell (split_valid_port_specsin setup-iptables.sh). Dangerous ports blocked even with explicit user request (src/squid/validation.ts:validateAndSanitizeHostAccessPort).--agent-image: Restricted to approved patterns only (src/domain-utils.ts:SAFE_BASE_IMAGE_PATTERNS) β official Ubuntu, catthehacker runner images, or SHA256-pinned. Prevents supply chain attacks via custom base images without--build-local.Port specification leading-zero rejection (
setup-iptables.sh:27): Rejects080to prevent octal interpretation, aligned with TypeScriptisValidPortSpec().entrypoint.sh, ~startup secondsagent-service.ts:93--allow-urlspatternsdomain-matchers.ts:parseUrlPatterns--enable-dind) grants full container escapesrc/dind-bootstrap.tsAWF_ALLOW_HOST_PORTSenv var fallback without strict validation if container/CLI version mismatchsetup-iptables.sh:409AWF_VALID_ALLOW_HOST_PORTSpreferred; shell secondary validation presentpolicy-manifest.ts:DANGEROUS_PORTS--allow-host-portsrequiredssl-bump.ts:usingTmpfsupstream-proxy.tssetup-iptables.sh:477setup-iptables.shπ― Attack Surface Map
--allow-domainsCLI βvalidateDomainOrPattern()βsquid.conf--allow-urlsCLI βparseUrlPatterns()β Squidurl_regexassertSafeForSquidConfigapplied, backslash allowed for regex escapingOUTPUTchain172.30.0.10:3128/proc/1/environ,docker-compose.yml, SSL CA key--enable-dindβ/var/run/docker.sockbind mount--enable-host-access+--allow-host-ports--agent-imagecustom value--build-localrequiredπ Evidence Collection
Command: npm audit
Command: grep for SYS_ADMIN/cap_add/cap_drop patterns
Command: grep for AWF_CHROOT_ENABLED
Command: grep for dangerous ports
Command: seccomp profile default action
Command: Squid injection char validation
β Recommendations
π΄ High Priority
H1 β Document and gate DinD socket exposure risk (
src/dind-bootstrap.ts, CLI--enable-dind)The Docker socket bind-mount is a full container escape vector. Consider adding a mandatory acknowledgment flag (e.g.,
--enable-dind-i-understand-the-risk) or a prominent runtime warning when--enable-dindis used in non-CI contexts. Current documentation notes the risk but there is no runtime friction.H2 β Harden dangerous-port list: add Docker API and common dev-server ports
Port 2375 (Docker API unencrypted), 2376 (Docker API TLS), 8080, 8443, 9090 (Prometheus), 4040 are absent from
DANGEROUS_PORTS. An agent aware of the host network could reach these services via--enable-host-access.File:
src/squid/policy-manifest.tsπ‘ Medium Priority
M1 β AppArmor custom profile instead of unconfined (
src/services/agent-service.ts:93)Currently
apparmor:unconfineddisables Docker's AppArmor guard. A narrow custom AppArmor profile that allows only the specificmountcall needed for procfs (typeproc, flagshidepid=2) would restore AppArmor as a defense-in-depth layer without blocking SYS_ADMIN+mount. This is non-trivial but would eliminate the AppArmor coverage gap.M2 β SYS_ADMIN window explicit test (
entrypoint.sh)Add an integration test that verifies
SYS_ADMINis absent from/proc/self/statuscapabilities after the agent process starts. This guards against regressions wherecapshis skipped (e.g.,AWF_CHROOT_ENABLEDnot being set).M3 β Rate-limit tuning for LOG rules (
setup-iptables.sh:477)The LOG rules use
--limit 5/min --limit-burst 10. A short burst attack (e.g., 100 connection attempts in 1 second) would only log the first 10, leaving 90 attempts invisible in audit logs. Consider raising burst to 50 or adding per-IP rate limiting with--hashlimit.M4 β SSL Bump CA key fallback logging (
src/ssl-bump.ts)When tmpfs mount fails (common in non-root environments), the CA key falls back to disk with only a
logger.debugmessage. Raise tologger.warnto ensure operators are notified that key material is on disk.π’ Low Priority
L1 β
--allow-urlsregex complexity limitUser-supplied URL patterns accepted by
--allow-urlscould include high-complexity regexes that stress Squid's POSIX regex engine. Add a maximum length check (e.g., 500 chars) and reject patterns containing recursive constructs ((?:...), lookahead, etc.) that are not needed for URL matching.L2 β
AWF_ALLOW_HOST_PORTSfallback removalsetup-iptables.sh:409falls back to unvalidatedAWF_ALLOW_HOST_PORTSifAWF_VALID_ALLOW_HOST_PORTSis absent (version mismatch scenario). Consider emitting a clear error and aborting rather than processing potentially unvalidated port specs.L3 β HTTP traffic operator visibility
The intentional omission of
http_proxy(httpoxy mitigation) means HTTP-blocked requests produce a different error UX than HTTPS-blocked requests. Add a startup log message explaining this so operators don't misdiagnose HTTP blocks as infrastructure failures.π 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