[Security Review] Daily Security Review — 2026-04-07 #1749
Closed
Replies: 1 comment
-
|
This discussion was automatically closed because it expired on 2026-04-14T13:35:28.036Z.
|
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
Security posture of
gh-aw-firewallis strong. The defense-in-depth architecture (iptables → Squid ACL → seccomp → capability drops → chroot → credential hiding) provides multiple independent enforcement layers. The most recent firewall escape test confirmed that the agent's prompt-injection defenses are working: a supplied adversarial payload was detected and refused outright, with zero bypass of security controls. Seven lines of architectural concern are noted below; none are critical.Key metrics:
🔍 Findings from Firewall Escape Test
Date of test: 2026-04-04 15:16:58 UTC
Result: ✅ All escape attempts refused
The escape test workflow provided an adversarial prompt via
xpia.mdand attempted to direct the agent to perform:The agent correctly identified the prompt injection and produced only a
noopoutput with message:The
GH_AW_SECRET_VERIFICATION_RESULT: successfield confirms the API proxy credential isolation also held. No token leakage occurred.🛡️ Architecture Security Analysis
Network Security Assessment
Container-level (setup-iptables.sh)
--security-opt no-new-privileges:trueis applied (line 1263) preventing setuid/sudo escalation.Domain Validation Assessment
All domains and URL patterns pass through
assertSafeForSquidConfig()before Squid config interpolation. The backslash character is excluded from SQUID_DANGEROUS_CHARS intentionally (needed for URL regex patterns), but domain names have a separate validation step that rejects it.ReDoS protection:
DOMAIN_CHAR_PATTERN = '[a-zA-Z0-9.-]*'(line 91) uses a character class rather than unbounded.+to prevent catastrophic backtracking in regex generation.Input Validation Assessment
Shell escaping:
Correct single-quote wrapping with internal single-quote escaping. Used for multi-arg invocations only; single-arg shell commands are passed as-is to
bash -cby design (to preserve$VARexpansion inside the sandbox).Port validation:
isValidPortSpec()rejects leading zeros and validates bounds 1–65535 on both TypeScript (host-iptables.ts:27–37) and Bash (setup-iptables.sh:185–196) sides./tmpon host/tmp:/tmp:rwis bidirectional (docker-manager.ts:824, 887)assertSafeForSquidConfigat domain parse timesquid-logs:/var/log/squid; agent lacks access/proc/1/environduring 5-second startup windowunset_sensitive_tokens/etc/passwdvia bind mount/etc/passwdmounted ro for UID lookup; no secrets in passwdcapsh --dropno-new-privileges+ seccomp default-deny/dev/nullunshareunshareallowed in seccomp but NET_ADMIN never granted🎯 Attack Surface Map
--allow-domainsCLI flagSQUID_DANGEROUS_CHARSregex +assertSafeForSquidConfig()(domain-patterns.ts:27, squid-config.ts:63)/var/run/docker.sock/dev/null~/.config/gh/hosts.yml,~/.npmrc,~/.cargo/credentials/dev/nulloverlays (docker-manager.ts:1134–1163)/proc/1/environcapsh --drop+no-new-privileges+ seccomp SCMP_ACT_ERRNO default📋 Evidence Collection
IPv6 disabling (setup-iptables.sh:47–49)
ptrace blocked in seccomp (containers/agent/seccomp-profile.json:364–371)
{ "names": ["ptrace", "process_vm_readv", "process_vm_writev"], "action": "SCMP_ACT_ERRNO", "errnoRet": 1 }Docker socket shadowing (src/docker-manager.ts:1039–1041)
Token 5-second unset window (containers/agent/entrypoint.sh:789–796)
Shared /tmp mount (src/docker-manager.ts:824, 887)
Credential file /dev/null overlays (src/docker-manager.ts:1134–1163)
✅ Recommendations
🔴 High — Should Fix Soon
H1. Explicitly block ICMP in the container's OUTPUT filter chain
File: containers/agent/setup-iptables.sh
The container-level iptables OUTPUT chain drops TCP and UDP (lines 421–425) but has no explicit DROP for ICMP. ICMP ping currently exits the container-level chain and reaches the host-level FW_WRAPPER REJECT, but this relies solely on host-level enforcement. Adding
iptables -A OUTPUT -p icmp -j DROPafter the TCP/UDP drops would provide defense-in-depth and eliminate any ICMP-based covert channel or ICMP tunneling attempt.H2. Reduce the token-unset delay or make it event-driven
File: containers/agent/entrypoint.sh:789–793
There is a hardcoded
sleep 5beforeunset_sensitive_tokensruns. This 5-second window leaves sensitive tokens (ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.) readable via/proc/1/environ. While the one-shot-token LD_PRELOAD library mitigates runtime reads from the agent, a race condition or a pre-forked subprocess could read the tokens during this window. Consider using a readiness signal from the agent process (e.g., a signal file) rather than a fixed sleep, to minimize the exposure window.🟡 Medium — Plan to Address
M1. Restrict
/tmpto a container-private tmpfs instead of bind-mounting the host's/tmpFile: src/docker-manager.ts:824, 887
Both chroot and non-chroot modes mount
/tmp:/tmp:rw(and/tmp:/host/tmp:rw), giving the agent bidirectional write access to the host's/tmp. A malicious agent or compromised tool could drop world-readable files in the host/tmpthat are later executed by other processes. Consider replacing the host/tmpbind mount with a container-private tmpfs (tmpfs:/tmp:rw), passing only a narrow subdirectory (e.g., theinit-signaldirectory) through an explicit volume.M2. Scope DNS exfiltration monitoring
File: containers/agent/setup-iptables.sh:143–162
DNS traffic to whitelisted resolvers (e.g., 8.8.8.8) is permitted and represents a potential low-bandwidth data exfiltration channel via crafted subdomain names (DNS tunneling). The iptables LOG rules already capture blocked UDP, but allowed DNS queries are not logged. Enabling DNS query logging via Squid's
dns_nameserversoption or by proxying DNS through a local resolver with query logging would improve audit coverage without breaking functionality.M3. Limit
unsharein seccomp profileFile: containers/agent/seccomp-profile.json:340
unshareis permitted in the seccomp profile. While the agent lacks NET_ADMIN to create network namespaces,unsharewith the--userflag (CLONE_NEWUSER) can still be invoked. On kernels withunprivileged_userns_clone=1, this could enable user namespace creation. Consider restrictingunsharesyscall args to block CLONE_NEWUSER (flags & 0x10000000) using a seccompargsfilter, or removing it if not required by any supported tool.🟢 Low — Nice to Have
L1. Pin Squid container image to a specific digest rather than
ubuntu/squid:latestUnpinned
latesttags introduce supply-chain risk. Using a specific digest (e.g.,ubuntu/squid@sha256:...) ensures reproducibility and eliminates the risk of a malicious or accidentally-broken upstream image being pulled between runs.L2. Add a rate-limiting configuration to Squid for CONNECT requests
No rate-limiting is configured on the Squid forward proxy. While the domain ACL prevents unauthorized destinations, a runaway agent loop could saturate external services. Adding
delay_poolswith per-client limits would cap bandwidth usage and provide an observable anomaly signal.L3. Audit
~/.configmount scopeFile: src/docker-manager.ts:906
The entire
~/.configdirectory is mounted, with credential files within it hidden via/dev/nulloverlays (lines 1134–1163). This relies on the/dev/nulloverlay being correctly processed by Docker on every code path. A regression (e.g., a new credential file added to~/.confignot covered by the blocklist) would silently expose it. Consider an allowlist approach: mount only specific known-safe subdirectories of~/.configrather than the full directory.📈 Security Metrics
Beta Was this translation helpful? Give feedback.
All reactions