[Security Review] Daily Security Review and Threat Modeling — 2026-03-26 #1451
Closed
Replies: 1 comment
-
|
This discussion was automatically closed because it expired on 2026-04-02T14:07:38.441Z.
|
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
The firewall demonstrates a strong, defense-in-depth security posture. The dual-layer network filtering (host DOCKER-USER chain + container OUTPUT chain), Squid L7 domain enforcement, and one-shot token protection represent well-implemented security controls. The dependency supply chain is healthy (
npm auditreports 0 vulnerabilities).Four issues of varying severity are documented below, none of which are immediately exploitable under default configuration.
unconfinedduring container initredactSecretscovers limited token formats🛡️ Architecture Security Analysis
Network Security Assessment ✅
Evidence gathered:
# Analyzed containers/agent/setup-iptables.sh and src/host-iptables.tsDual-layer filtering is correctly implemented:
Container-level (OUTPUT chain) —
setup-iptables.sh:RETURN(not redirected to Squid) thenDROPDROPDROP(blocks unauthorized DNS exfiltration)Host-level (DOCKER-USER → FW_WRAPPER chain) —
src/host-iptables.ts:172.30.0.10) getsACCEPT(unrestricted outbound)ESTABLISHED,RELATEDACCEPTACCEPTACCEPTACCEPT224.0.0.0/4), link-local (169.254.0.0/16)REJECTREJECTwith loggingREJECT— covers ICMP and other protocolsIPv6: If
ip6tablesunavailable, IPv6 disabled via sysctl (net.ipv6.conf.all.disable_ipv6=1). ✅DNS validation:
parseDnsServers()enforces strict IPv4/IPv6 format before DNS servers are used in iptables rules. ✅Finding: ICMP only blocked at host level (Low)
setup-iptables.shdrops TCP and UDP explicitly but does not explicitly drop ICMP in the container OUTPUT chain:ICMP is caught by the host FW_WRAPPER catch-all REJECT (step 8). However, if host-level rules are absent (e.g., race condition during startup, or partial setup failure), ICMP ping-tunneling to external IPs could leak data. Defense-in-depth would add an explicit ICMP DROP in the container chain.
Container Security Assessment
Evidence gathered:
# Analyzed src/docker-manager.ts lines 1100-1133, containers/agent/entrypoint.shCapabilities:
Seccomp profile (
containers/agent/seccomp-profile.json):defaultAction: SCMP_ACT_ERRNO— fail-closed (all unknown syscalls blocked)Resource limits (src/docker-manager.ts:1130-1133):
mem_limit: 6g,pids_limit: 1000,cpu_shares: 1024Finding: AppArmor
unconfinedduring init (Medium)The agent container runs
apparmor:unconfinedto allowmount -t procof a container-scoped procfs at/host/proc(needed for .NET CLR, JVM). While SYS_ADMIN is dropped viacapshbefore user code runs, the entrypoint.sh runs as root withSYS_ADMIN + apparmor:unconfinedduring the initialization window. Any vulnerability in the entrypoint logic (e.g., TOCTOU between procfs mount and capsh drop) could be leveraged in this window. A targeted AppArmor profile that allows only themountoperation needed would reduce this surface.Positive: Docker socket is hidden by default:
Docker-in-Docker (
--enable-dind) explicitly warns of firewall bypass risk.Credential Protection Assessment ✅
one-shot token library (
containers/agent/one-shot-token/one-shot-token.c):getenv()via LD_PRELOADunsetenv()unset_sensitive_tokensto clear envFinding: 5-second token exposure window (Low)
Any subprocess or
/proc/1/environread within the first 5 seconds retains access to all tokens. This window is intentional (to allow the agent process to initialize and cache tokens via LD_PRELOAD), but represents a race condition. Reducing the sleep or using a synchronization mechanism (e.g., the one-shot library signals readiness) could close this window.API proxy credential isolation: When
--enable-api-proxyis active, real API keys are excluded from agent environment (EXCLUDED_ENV_VARSset). The agent only sees placeholder tokens. ✅Information: XOR obfuscation of token names is weak (Info)
XOR with a static key is trivially reversed. The comment acknowledges this: "NOT cryptographic protection — a determined attacker can reverse the XOR." Acceptable for the stated goal (prevent
stringsdiscovery), but should not be relied on for any actual security guarantee.Domain Validation Assessment ✅
Evidence gathered:
# Analyzed src/domain-patterns.ts in full*converts to[a-zA-Z0-9.-]*(not.*) — prevents ReDoS catastrophic backtracking ✅*and*.*explicitly rejected ✅*.*.*) ✅(domain.com/redacted) vs(domain.com/redacted)`) ✅dstdomainadds a leading dot to match both exact domain and subdomains ✅Finding: Squid port exposed to host (Medium)
Any process on the host (or any container on the bridge) can use
(localhost/redacted) as a proxy and reach domains in the allowlist. The agent's domain ACL is enforced (so only allowed domains are reachable), but the network isolation is broader than intended: it's not restricted to only the agent container. This is partially intentional (needed forawf logs` commands) but could be exploited by a compromised sibling container or CI job step running alongside AWF.Input Validation & Injection Assessment ✅
Shell metacharacters in agentCommand:
The
$$$$escaping is for Docker Compose YAML variable interpolation only. The command is still interpreted by/bin/bash -c, so shell metacharacters inagentCommand(semicolons, backticks,$()) are executed as intended — this is the user's own shell command, not untrusted input, so this is by design and not a vulnerability.DNS server injection:
parseDnsServers()validates strict IPv4/IPv6 format — command injection via--dns-serversis not possible. ✅--enable-dlpby default (opt-out)--enable-dindexplicitly warned🎯 Attack Surface Map
--allow-domainsinputdomain-patterns.ts:1--dns-serversinputcli.ts:828agentCommandshelldocker-manager.ts:1148docker-manager.ts:377entrypoint.sh:396entrypoint.sh:709--enable-dindflagdocker-manager.ts:882AWF_DNS_SERVERSenv varsetup-iptables.sh:129host-iptables.ts:418✅ Recommendations
🔴 Medium Priority
1. Restrict Squid port binding to container network only
Change Squid port binding to avoid exposing it on the host loopback:
If
awf logscommands need to reach Squid externally, document this requirement and scope the binding accordingly.2. Create a targeted AppArmor profile for the agent container
Instead of
apparmor:unconfined, write a minimal AppArmor profile that allows only themount -t procoperation needed for/host/proc. This reduces the initialization attack surface while maintaining the functionality needed by .NET and JVM runtimes.🟡 Low Priority
3. Add explicit ICMP DROP in container OUTPUT chain
In
containers/agent/setup-iptables.sh, add an explicit ICMP drop with logging for audit visibility:This provides container-level defense-in-depth and adds audit logging for ICMP-based exfiltration attempts.
4. Reduce or eliminate the one-shot token exposure window
The 5-second
sleepbeforeunset_sensitive_tokenscreates a window where/proc/1/environexposes all tokens. Options:🟢 Informational
5. Consider making DLP opt-out instead of opt-in
The
--enable-dlpflag enables URL scanning for credential patterns. Given the sensitive nature of AI agent workflows, enabling this by default (with--disable-dlpto turn off) would provide better default security for users who don't know about it.6. Expand
redactSecretspatternssrc/redact-secrets.tscovers Bearer tokens and common key patterns but misses some formats (e.g., AWSAKIA*, Slackxoxb-*). While this function is used for logging redaction (not enforcement), expanding it reduces accidental secret logging.📋 Evidence Collection
Commands run during this review
📈 Security Metrics
Beta Was this translation helpful? Give feedback.
All reactions