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
This daily security review analyzed the gh-aw-firewall codebase against the complementary Secret Digger escape-test results from 2026-04-11. The overall security posture is strong, with multiple layered defenses (seccomp allowlist, capability dropping, iptables default-deny, domain validation, one-shot token isolation, tmpfs overlays). One medium-severity gap was identified (ICMP covert channel) and several lower-risk observations are noted below.
Interpretation: The secret-digger agent ran under AWF containment and was unable to exfiltrate any secrets. This provides positive evidence that credential isolation (one-shot tokens, env-unset, API proxy BYOK pattern) is functioning correctly.
🛡️ Architecture Security Analysis
Network Security Assessment
Evidence gathered:
# Container iptables final DROP rules (containers/agent/setup-iptables.sh:427-430)
iptables -A OUTPUT -p tcp -m limit --limit 10/min --limit-burst 20 -j LOG ...
iptables -A OUTPUT -p tcp -j DROP
iptables -A OUTPUT -p udp -m limit --limit 10/min --limit-burst 20 -j LOG ...
iptables -A OUTPUT -p udp -j DROP
Strengths:
Default-deny on TCP and UDP egress from agent container
DNAT on ports 80/443 to Squid (fallback for proxy-unaware tools)
DNS restricted to Docker embedded DNS (127.0.0.11) → upstream allow-listed servers
IPv6 disabled via sysctl when ip6tables unavailable (containers/agent/setup-iptables.sh:48-49)
Dangerous ports (SSH/22, SMTP/25, DBs) logged and blocked at both iptables and Squid layers
⚠️ Gap — ICMP not filtered (Medium):
The setup-iptables.sh OUTPUT chain drops TCP and UDP, but never adds a DROP or LOG rule for ICMP (protocol 1). Any traffic that isn't TCP or UDP exits without restriction. Tools like ping and ICMP-based tunneling utilities (e.g., ptunnel, icmptunnel) could use this as an unmonitored data exfiltration channel. Bandwidth is limited but the channel is entirely invisible to Squid and the current audit logs.
# No ICMP rules in setup-iptables.sh
grep "icmp\|proto" containers/agent/setup-iptables.sh
# → (no output)
Recommendation: Add at the end of setup-iptables.sh, after the UDP DROP:
# Block and log all other protocols (ICMP, GRE, etc.) — default deny
iptables -A OUTPUT -m limit --limit 5/min -j LOG --log-prefix "[FW_BLOCKED_OTHER] " --log-level 4 --log-uid
iptables -A OUTPUT -j DROP
NET_ADMIN never granted to agent — only to the isolated iptables-init init container (src/docker-manager.ts:1647-1648)
no-new-privileges: true on all containers prevents setuid/setgid escalation
Docker socket hidden by default: mapped to /dev/null (src/docker-manager.ts:1313-1315)
UID/GID validated as numeric and non-zero before usermod/groupmod (containers/agent/entrypoint.sh:15-33)
tmpfs overlays hide workDir (squid config) and MCP logs from the agent (src/docker-manager.ts:1484-1508)
Observation — Docker socket exposure when --enable-dind is used:
# src/docker-manager.ts:1303-1308
logger.warn('Docker-in-Docker enabled: agent can run docker commands (firewall bypass possible)');
agentVolumes.push(`\$\{dockerSocketPath}:/host\$\{dockerSocketPath}:rw`);
When --enable-dind is explicitly opted into, the Docker daemon socket is mounted into the agent, allowing docker run --network host which bypasses all AWF network controls. This is documented and requires explicit opt-in, but operators should be aware that --enable-dind effectively negates network containment.
Domain Validation Assessment
Evidence gathered:
# src/domain-patterns.ts:27export const SQUID_DANGEROUS_CHARS = /[\s\0"'`;#]/;# src/squid-config.ts:99-110 (assertSafeForSquidConfig)function assertSafeForSquidConfig(value: string): string { if (SQUID_DANGEROUS_CHARS.test(value)) { throw new Error('SECURITY: Domain or pattern contains characters unsafe for Squid config...'); } return value;}# Wildcard conversion (src/domain-patterns.ts:109)const DOMAIN_CHAR_PATTERN = '[a-zA-Z0-9.-]*';// Uses character class instead of .* — prevents ReDoS
Strengths:
All domains validated against SQUID_DANGEROUS_CHARS before config interpolation — prevents Squid config injection via newline/comment/semicolon characters
Wildcard * → [a-zA-Z0-9.-]* character class prevents catastrophic backtracking (ReDoS)
Defense-in-depth: assertSafeForSquidConfig() called at both parse time (parseDomainList) and config generation time (formatDomainForSquid)
Protocol-specific domains ((redacted) vs https://) correctly mapped to separate Squid ACLs with !CONNECT rules
Port specifications validated before use in iptables rules
Gateway IPs validated against IPv4 regex before interpolation
Shell argument escaping via escapeShellArg() (src/cli.ts:1052)
Dollar signs doubled in agent command to prevent variable expansion in Docker CMD context
Observation — --env-all passthrough:
# src/cli.ts:2013-2015if (options.envAll) {
logger.warn('⚠️ Using --env-all: All host environment variables will be passed to container');```When `--env-all` is used, all host environment variables (including any secrets present) are passed to the agent container. The proxy env vars (`HTTP_PROXY`, etc.) are excluded via `PROXY_ENV_VARS` (`src/upstream-proxy.ts:11-26`), but other secrets (e.g., `AWS_SECRET_ACCESS_KEY`, `DATABASE_URL`) would be exposed. This is expected behavior forthe flag but should be treated as a high-risk optionin CI pipelines.---## ⚠️ Threat Model (STRIDE)| Category | Threat | File:Line | Likelihood | Impact | Severity ||---|---|---|---|---|---||**S**poofing | Agent impersonates API proxy by guessing `172.30.0.30`|`src/docker-manager.ts:1769`| Low (fixed IP, network-isolated) | High |**Low**||**T**ampering | Agent modifies Squid config via workDir (before tmpfs overlay) |`src/docker-manager.ts:1484`| Low (tmpfs applied before start) | Critical |**Low**||**T**ampering | ICMP covert channel for data exfiltration |`containers/agent/setup-iptables.sh:427-430`|**Medium**| Medium |**Medium**||**R**epudiation | Squid logs owned by proxy user, agent can't delete them | `containers/squid/entrypoint.sh` | Low | Medium | **Low** || **I**nformation Disclosure | `/proc/1/environ` read before token unset completes | `containers/agent/entrypoint.sh:836` | Low (1s window) | High | **Low-Medium** || **I**nformation Disclosure | `--env-all` passes all host env vars to container | `src/cli.ts:2015` | Medium (if misconfigured) | High | **Medium** || **I**nformation Disclosure | SSL Bump CA key on host tmpfs accessible to host root | `src/ssl-bump.ts` | Low (requires host compromise) | High | **Low** || **D**enial of Service | ReDoS via malicious domain pattern in `--allow-domains` | `src/domain-patterns.ts:109` | Low (character class used) | Medium | **Low** || **D**enial of Service | Docker subnet pool exhaustion from orphaned networks | `scripts/ci/cleanup.sh` | Medium (CI without cleanup) | Medium | **Low** (mitigated by cleanup scripts) || **E**levation of Privilege | Docker-in-Docker firewall bypass via `docker run --network host` | `src/docker-manager.ts:1303` | Low (requires explicit `--enable-dind`) | Critical | **Medium** (by design, opt-in) || **E**levation of Privilege | LD_PRELOAD bypass by native-code agent | `containers/agent/entrypoint.sh:528` | Low (requires agent executing binary) | High | **Low-Medium** |---## 🎯 Attack Surface Map| Surface | Location | Current Protections | Risk ||---|---|---|---|| **Agent TCP/UDP egress** | `containers/agent/setup-iptables.sh:427-430` | Default-deny DROP, Squid ACL, LOG | ✅ Low || **Agent ICMP egress** | *(absent)* | **None** | ⚠️ Medium || **DNS egress** | `setup-iptables.sh:383-399` | Restricted to Docker DNS + allow-listed upstreams | ✅ Low || **Domain allow-list parsing** | `src/domain-patterns.ts` | Char class regex, SQUID_DANGEROUS_CHARS rejection | ✅ Low || **Squid config injection** | `src/squid-config.ts:99-110` | `assertSafeForSquidConfig()` double-checked | ✅ Low || **Container capabilities** | `src/docker-manager.ts:1529-1543` | `cap_drop: ALL` + selective allow only for init | ✅ Low || **Agent privilege escalation** | `containers/agent/entrypoint.sh:833` | `capsh --drop`, `no-new-privileges`, seccomp allowlist | ✅ Low || **Token leakage via /proc** | `containers/agent/entrypoint.sh:836-903` | One-shot LD_PRELOAD + parent shell unset after 1s | ✅ Low || **Docker socket** | `src/docker-manager.ts:1311-1315` | Mapped to `/dev/null` by default | ✅ Low || **Docker-in-Docker (opt-in)** | `src/docker-manager.ts:1303-1308` | Warning logged; firewall bypass documented | ⚠️ Medium (by design) || **`--env-all` secret passthrough** | `src/cli.ts:2013` | Warning only; proxy vars excluded | ⚠️ Medium || **SSL Bump MITM CA** | `src/ssl-bump.ts` | tmpfs-backed key; agent trusts AWF CA | i️ Low (opt-in) || **Host iptables DOCKER-USER** | `src/host-iptables.ts:237-590` | FW_WRAPPER dedicated chain; cleanup on exit | ✅ Low |---## 📋 Evidence Collection<details><summary>npm audit (0 vulnerabilities)</summary>```Total vulnerabilities: 0Audit metadata: {'info': 0, 'low': 0, 'moderate': 0, 'high': 0, 'critical': 0, 'total': 0}```</details><details><summary>Seccomp profile analysis</summary>```defaultAction: SCMP_ACT_ERRNO ← deny-by-default (allowlist)Total syscall rules: 5Blocked groups: 3 (ptrace/process_vm_*, kexec_*/reboot/init_module/finit_module, umount/umount2)Allowed entries: 2 rules (~345 total syscall names)
ICMP gap evidence
# containers/agent/setup-iptables.sh final OUTPUT rules:
iptables -A OUTPUT -p tcp -j DROP # line 428
iptables -A OUTPUT -p udp -j DROP # line 430# No rule for: iptables -A OUTPUT -p icmp -j DROP# No rule for: iptables -A OUTPUT -j DROP (catch-all)# grep icmp containers/agent/setup-iptables.sh → (no output)
Domain validation evidence
# src/domain-patterns.ts:27export const SQUID_DANGEROUS_CHARS = /[\s\0"'`;#]/;# Wildcard conversion: * → [a-zA-Z0-9.-]* (ReDoS-safe)# assertSafeForSquidConfig() called at every interpolation point
File:containers/agent/setup-iptables.sh (after line 430)
The agent container's iptables OUTPUT chain drops TCP and UDP but has no rule for ICMP or other IP protocols. Add a catch-all DROP after the UDP rule:
# After: iptables -A OUTPUT -p udp -j DROP# Block all other protocols (ICMP, GRE, SCTP, etc.)
iptables -A OUTPUT -m limit --limit 5/min --limit-burst 10 \
-j LOG --log-prefix "[FW_BLOCKED_OTHER] " --log-level 4 --log-uid
iptables -A OUTPUT -j DROP
This closes the ICMP covert channel and provides defense against any other protocol-based bypass.
🟡 Medium — Document --enable-dind Firewall Bypass Clearly
File:README.md, docs/environment.md
The warning at src/docker-manager.ts:1303 is logged at runtime but is not prominently documented in user-facing docs. Add a security callout warning operators that --enable-dind fully negates network containment and should only be used in already-trusted environments.
🟡 Medium — Strengthen --env-all Guard
File:src/cli.ts (~line 2013)
Consider scanning env vars passed via --env-all for known secret patterns (e.g., _KEY, _SECRET, _TOKEN, _PASSWORD) and emitting a specific per-variable warning, or add a --env-all-allow-secrets flag to make the risk explicit at a per-variable level. Currently only a single generic warning is shown.
🟢 Low — Add ICMP to iptables Audit Logging
Even before blocking ICMP, add a LOG+DROP for ICMP in the audit logging section to make ICMP attempts visible in dmesg/kernel logs. This provides observability without changing the allow/deny posture.
🟢 Low — Document Secret Digger Test Coverage
Add a reference in docs/INTEGRATION-TESTS.md linking to the Secret Digger workflow results so operators can track credential isolation test outcomes longitudinally.
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
This daily security review analyzed the gh-aw-firewall codebase against the complementary Secret Digger escape-test results from 2026-04-11. The overall security posture is strong, with multiple layered defenses (seccomp allowlist, capability dropping, iptables default-deny, domain validation, one-shot token isolation, tmpfs overlays). One medium-severity gap was identified (ICMP covert channel) and several lower-risk observations are noted below.
SCMP_ACT_ERRNOdefault, ~345 allowed syscalls)ALL(agent + API proxy + DoH proxy)/dev/null)🔍 Findings from Firewall Escape Test (Secret Digger, 2026-04-11)
The escape test log (
/tmp/gh-aw/escape-test-summary.txt) shows workflow-level telemetry for the Secret Digger (Copilot) run:GH_AW_SECRET_VERIFICATION_RESULT: successAgent succeeded with only noop outputs— no secrets were found or leakedGH_AW_INFERENCE_ACCESS_ERROR: false— inference access was properly controlledGH_AW_LOCKDOWN_CHECK_FAILED: false— lockdown mode respectedInterpretation: The secret-digger agent ran under AWF containment and was unable to exfiltrate any secrets. This provides positive evidence that credential isolation (one-shot tokens, env-unset, API proxy BYOK pattern) is functioning correctly.
🛡️ Architecture Security Analysis
Network Security Assessment
Evidence gathered:
# Container iptables final DROP rules (containers/agent/setup-iptables.sh:427-430) iptables -A OUTPUT -p tcp -m limit --limit 10/min --limit-burst 20 -j LOG ... iptables -A OUTPUT -p tcp -j DROP iptables -A OUTPUT -p udp -m limit --limit 10/min --limit-burst 20 -j LOG ... iptables -A OUTPUT -p udp -j DROPStrengths:
containers/agent/setup-iptables.sh:48-49)DOCKER-USERchain (src/host-iptables.ts:566) provides cross-container enforcementThe
setup-iptables.shOUTPUT chain drops TCP and UDP, but never adds a DROP or LOG rule for ICMP (protocol 1). Any traffic that isn't TCP or UDP exits without restriction. Tools likepingand ICMP-based tunneling utilities (e.g.,ptunnel,icmptunnel) could use this as an unmonitored data exfiltration channel. Bandwidth is limited but the channel is entirely invisible to Squid and the current audit logs.Recommendation: Add at the end of
setup-iptables.sh, after the UDP DROP:Container Security Assessment
Evidence gathered:
Strengths:
ptrace,process_vm_readv/writevblocked — prevents cross-process memory inspectionkexec_load,reboot,init_moduleblocked — prevents kernel-level attacksumount/umount2blocked — prevents unmounting security-relevant filesystem overlays (tmpfs hiding workDir)src/docker-manager.ts:1647-1648)no-new-privileges: trueon all containers prevents setuid/setgid escalation/dev/null(src/docker-manager.ts:1313-1315)usermod/groupmod(containers/agent/entrypoint.sh:15-33)src/docker-manager.ts:1484-1508)Observation — Docker socket exposure when
--enable-dindis used:When
--enable-dindis explicitly opted into, the Docker daemon socket is mounted into the agent, allowingdocker run --network hostwhich bypasses all AWF network controls. This is documented and requires explicit opt-in, but operators should be aware that--enable-dindeffectively negates network containment.Domain Validation Assessment
Evidence gathered:
Strengths:
SQUID_DANGEROUS_CHARSbefore config interpolation — prevents Squid config injection via newline/comment/semicolon characters*→[a-zA-Z0-9.-]*character class prevents catastrophic backtracking (ReDoS)assertSafeForSquidConfig()called at both parse time (parseDomainList) and config generation time (formatDomainForSquid)!CONNECTrulesInput Validation Assessment
Evidence gathered:
Strengths:
escapeShellArg()(src/cli.ts:1052)Observation —
--env-allpassthrough:ICMP gap evidence
Domain validation evidence
Docker socket protection
✅ Recommendations
🔴 Medium — ICMP Egress Not Blocked
File:
containers/agent/setup-iptables.sh(after line 430)The agent container's iptables OUTPUT chain drops TCP and UDP but has no rule for ICMP or other IP protocols. Add a catch-all DROP after the UDP rule:
This closes the ICMP covert channel and provides defense against any other protocol-based bypass.
🟡 Medium — Document
--enable-dindFirewall Bypass ClearlyFile:
README.md,docs/environment.mdThe warning at
src/docker-manager.ts:1303is logged at runtime but is not prominently documented in user-facing docs. Add a security callout warning operators that--enable-dindfully negates network containment and should only be used in already-trusted environments.🟡 Medium — Strengthen
--env-allGuardFile:
src/cli.ts(~line 2013)Consider scanning env vars passed via
--env-allfor known secret patterns (e.g.,_KEY,_SECRET,_TOKEN,_PASSWORD) and emitting a specific per-variable warning, or add a--env-all-allow-secretsflag to make the risk explicit at a per-variable level. Currently only a single generic warning is shown.🟢 Low — Add ICMP to iptables Audit Logging
Even before blocking ICMP, add a LOG+DROP for ICMP in the audit logging section to make ICMP attempts visible in
dmesg/kernel logs. This provides observability without changing the allow/deny posture.🟢 Low — Document Secret Digger Test Coverage
Add a reference in
docs/INTEGRATION-TESTS.mdlinking to the Secret Digger workflow results so operators can track credential isolation test outcomes longitudinally.📈 Security Metrics
Beta Was this translation helpful? Give feedback.
All reactions