GuardFall and the Shell Injection Illusion: Why Text-Based Command Filters Fail Every Coding Agent — and How Codex CLI's Kernel-Level Sandbox Renders the Entire Attack Class Irrelevant
GuardFall and the Shell Injection Illusion: Why Text-Based Command Filters Fail Every Coding Agent — and How Codex CLI’s Kernel-Level Sandbox Renders the Entire Attack Class Irrelevant
On 30 June 2026 Adversa AI disclosed GuardFall, a shell-interpretation bypass that affected ten of eleven surveyed open-source coding agents — tools collectively representing roughly 548,000 GitHub stars 1. The vulnerability is not a novel zero-day. It is a decades-old class of shell quoting and expansion tricks that defeats any safety layer built on string-matching raw command text. What makes GuardFall significant is not the technique but the sheer breadth of the failure: the design convention of “inspect the string, then hand it to bash” turns out to be structurally broken, and nearly every open-source agent inherited the same flaw.
This article dissects the five bypass classes Adversa demonstrated, examines why application-layer filtering cannot close the gap, and maps the findings onto Codex CLI’s kernel-level sandbox architecture — which sidesteps the entire attack surface by enforcing restrictions below the shell.
The Mismatch: Filter vs Shell
Every GuardFall variant exploits the same root cause. An agent’s safety layer inspects the raw command string for dangerous patterns — rm -rf, curl | bash, chmod 777 — and either blocks or allows the command. But bash does not execute raw text. Before any command runs, the shell applies quote removal, variable expansion, command substitution, globbing, and field splitting 2. The string the filter inspected is not the string the kernel executes.
sequenceDiagram
participant Agent as Coding Agent
participant Filter as Text-Based Filter
participant Bash as Bash Shell
participant Kernel as OS Kernel
Agent->>Filter: raw command string
Filter->>Filter: regex / blocklist check
Filter-->>Bash: "safe" string passed through
Bash->>Bash: quote removal, expansion, substitution
Bash->>Kernel: transformed argv[]
Note over Filter,Kernel: Filter saw "r''m" — Kernel executes "rm"
This is the same class of bug that web application firewalls have battled for two decades: a canonicalisation gap between the inspection layer and the execution layer 3.
The Five Bypass Classes
Adversa’s research identified five distinct evasion categories, each exploiting a different bash expansion mechanism 1:
1. Quote Removal
Bash silently strips matched quotes before execution. Inserting empty quotes into a blocked command changes the string without changing the result:
# Filter sees "r''m" — no match for "rm"
r''m -rf /important-directory
The filter’s pattern rm never matches. Bash strips the empty quotes and executes rm -rf /important-directory 1.
2. $IFS Expansion
The Internal Field Separator variable defaults to space-tab-newline. Substituting $IFS for literal spaces produces a single token to the filter but multiple arguments to bash:
# Filter sees one "word": rm$IFS-rf$IFS/
rm$IFS-rf$IFS/target
After expansion, bash receives rm, -rf, /target as three separate arguments 1.
3. Command Substitution
The $(...) or backtick syntax generates command names dynamically at runtime, invisible to static text matching:
# Filter sees "$(echo rm)" — no literal "rm" in the command
$(echo rm) -rf /target
Bash evaluates the subshell first, producing rm, then executes the outer command 1.
4. Base64 Pipeline Encoding
Encoding destructive payloads in base64 and piping through a decoder renders the command opaque to any text-based filter:
# Each segment is individually benign
echo "cm0gLXJmIC90YXJnZXQ=" | base64 -d | bash
No blocked keyword appears in the raw string. The shell reconstructs and executes rm -rf /target at runtime 1.
5. Alternative Destructive Argv Shapes
Standard Unix utilities can achieve destructive outcomes without invoking classically blocked commands:
# No "rm" anywhere — "find" with "-delete" is equally destructive
find /project -name "*.py" -delete
# Overwrite a disk — "dd" is rarely blocked
dd if=/dev/zero of=/dev/sda bs=1M
# Install a setuid backdoor
install -m 4755 payload /usr/bin/backdoor
These commands are legitimate tools used daily. No blocklist can categorically ban find or dd without breaking normal workflows 1.
Who Was Affected
Adversa tested eleven open-source agents. Ten were vulnerable 1:
| Agent | Stars (approx.) | Vulnerable |
|---|---|---|
| OpenHands | 53,000 | Yes |
| Aider | 36,000 | Yes |
| Open Interpreter | 58,000 | Yes |
| Cline | 42,000 | Yes |
| Goose | 18,000 | Yes |
| SWE-agent | 19,000 | Yes |
| Roo-Code | 24,000 | Yes |
| Plandex | 12,000 | Yes |
| opencode | 8,000 | Yes |
| Hermes | 5,000 | Yes |
| Continue | 35,000 | No |
Continue survived because it implements bash-aware tokenisation — parsing the command through the same expansion rules bash uses — rather than matching against raw text 1. This is the correct approach at the application layer, but it is expensive to maintain: every bash release can change expansion semantics, and edge cases in quoting are notoriously difficult to enumerate 4.
Why Application-Layer Filtering Cannot Win
The fundamental problem is combinatorial. Bash’s expansion rules compose arbitrarily. A command can combine quote removal with $IFS expansion with command substitution with brace expansion simultaneously. The number of equivalent representations of any single command is unbounded 3.
Building a filter that correctly canonicalises all possible bash expansions means reimplementing bash’s parser. At that point you are no longer filtering — you are interpreting. And if your interpreter disagrees with the actual bash binary on any edge case, the gap is exploitable.
This is why the security community reached the same conclusion about web application firewalls a decade ago: you cannot secure the execution layer by inspecting input at a higher abstraction level 5.
How Codex CLI Sidesteps the Entire Class
Codex CLI does not attempt to solve GuardFall at the application layer. Instead, it enforces security constraints below the shell, at the operating system kernel, using platform-native mandatory access control 67:
graph TD
A[Agent generates command] --> B[Command handed to bash]
B --> C[Bash expands and executes]
C --> D{Kernel sandbox layer}
D -->|Write to allowed path| E[Permitted]
D -->|Write to blocked path| F[EACCES / denied]
D -->|Network connect| G[EACCES / denied]
style D fill:#1a1a2e,stroke:#e94560,stroke-width:3px,color:#fff
style F fill:#e94560,color:#fff
style G fill:#e94560,color:#fff
Linux: Landlock + seccomp-BPF
On Linux (kernel 5.13+), Codex uses a dedicated codex-linux-sandbox helper binary. Before executing any command, the helper 6:
-
Applies Landlock rules — granting read access broadly but restricting write operations to explicitly allowlisted directories (the workspace,
/tmp,/dev/null). Landlock operates at the VFS layer; no amount of bash expansion can change which filesystem paths the kernel permits. -
Installs a seccomp-BPF filter — blocking outbound network syscalls (
connect,accept,bind,listen,sendto,sendmsg) while exemptingAF_UNIXsockets for local IPC. This prevents data exfiltration regardless of how the network call was constructed. -
Calls
execvp— spawning the target command under the enforced restrictions.
The critical insight: Landlock and seccomp operate on syscall arguments and filesystem paths, not on command strings. A command constructed via $IFS expansion, base64 decoding, or command substitution still resolves to the same syscall with the same path argument — and the kernel enforces the same policy 6.
macOS: Seatbelt (sandbox-exec)
On macOS 12+, Codex uses Apple’s Seatbelt framework via sandbox-exec with a compiled profile matching the selected sandbox mode. Seatbelt enforces restrictions on file operations, network access, process spawning, and Mach port communication at the kernel level 7. The same principle applies: bash can expand commands however it likes, but the Mach kernel enforces the policy on the resulting operations.
Windows: AppContainer
On Windows, Codex uses AppContainer isolation with per-session security contexts, restricting filesystem and network access through the NT kernel’s capability-based model 7.
The Three Sandbox Modes
Codex CLI’s sandbox_mode setting in config.toml determines the enforcement level 8:
# Strictest — agent can only read, never write or connect
sandbox_mode = "read-only"
# Default — writes only within the workspace directory
sandbox_mode = "workspace-write"
# Escape hatch — full access (not recommended for untrusted repos)
sandbox_mode = "danger-full-access"
Even in workspace-write mode — the default — a GuardFall-style attack that constructs rm -rf / through shell expansion would be blocked by Landlock at the kernel level, because / is not in the write allowlist.
Defence in Depth: Layers Above the Kernel
Codex CLI does not rely solely on the kernel sandbox. Multiple layers compose to create defence in depth 89:
Approval Policy
The approval_policy setting gates tool calls before they reach the shell:
# Prompt the user before any write operation
approval_policy = "on-request"
# Auto-approve reads, prompt on writes
approval_policy = "writes"
In writes mode (introduced in v0.144.0), read-only operations proceed automatically while any write triggers a human approval prompt — or delegation to the Guardian auto-review agent 9.
Guardian Auto-Review
When approvals_reviewer = "guardian_subagent" is set, a separate LLM instance evaluates each pending command against a safety policy checking for data exfiltration, credential probing, persistent security weakening, and destructive actions. The Guardian operates independently of the primary agent and has no access to the agent’s prompt context 10.
PreToolUse Hooks
Custom hooks can inspect tool calls before execution, adding domain-specific constraints:
[[hooks]]
event = "PreToolUse"
tool = "shell"
command = "python3 /path/to/validate_command.py"
A PreToolUse hook could implement bash-aware tokenisation (like Continue’s approach) as an additional validation layer — but with Codex CLI, this is a supplementary check rather than the primary defence 8.
Network Proxy Domain Allowlist
The network_proxy setting restricts outbound connections to explicitly permitted domains, preventing exfiltration even if a command somehow bypasses the seccomp filter:
[network_proxy]
allowed_domains = ["github.com", "registry.npmjs.org"]
Practical Configuration for Untrusted Repositories
When cloning and working with repositories from unknown sources — the exact scenario where GuardFall payloads lurk in READMEs, Makefiles, and configuration files — use this hardened configuration:
# ~/.codex/untrusted.config.toml
# Activate with: codex --profile untrusted
sandbox_mode = "workspace-write"
approval_policy = "on-request"
approvals_reviewer = "guardian_subagent"
[network_proxy]
allowed_domains = [] # No network access
[auto_review]
enabled = true
Launch with codex --profile untrusted when evaluating unfamiliar code 8.
The Structural Lesson
GuardFall is not a bug report. It is a proof that the “inspect-then-execute” architecture for command safety is fundamentally broken. The fix is not better regex, longer blocklists, or more sophisticated string matching. The fix is moving the enforcement boundary below the abstraction layer that introduces ambiguity.
Codex CLI’s kernel-level sandbox does exactly this. Landlock does not parse bash. Seatbelt does not interpret shell expansions. They enforce policy on the operations the kernel actually performs, regardless of how those operations were constructed in userspace.
For the ten affected open-source agents, the remediation path is clear: adopt containerisation, kernel-level MAC (Landlock, Seatbelt, AppContainer), or both. Text-based command filtering should be treated as a diagnostic signal — useful for logging and alerting — but never as a security boundary 5.
Citations
-
Adversa AI, “AI Coding Agents Vulnerability: GuardFall Shell Injection,” adversa.ai, June 30, 2026. https://adversa.ai/blog/opensource-ai-coding-agents-shell-injection-vulnerability/ ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9
-
GNU Project, “Shell Expansions,” Bash Reference Manual, 2026. https://www.gnu.org/software/bash/manual/html_node/Shell-Expansions.html ↩
-
The Hacker News, “GuardFall Exposes Open-Source AI Coding Agents to Decades-Old Shell Injection Risks,” June 2026. https://thehackernews.com/2026/06/guardfall-exposes-open-source-ai-coding.html ↩ ↩2
-
Mallory, “GuardFall Shell Injection Bypass Affects Most Open-Source AI Coding Agents,” July 2026. https://www.mallory.ai/stories/019f1cce-b0d1-74aa-9190-6d9f06c5ca26 ↩
-
Security Affairs, “GuardFall Flaw Hits 10 of 11 Popular Open-Source AI Agents,” July 2026. https://securityaffairs.com/194546/ai/guardfall-flaw-hits-10-of-11-popular-open-source-ai-agents.html ↩ ↩2
-
OpenAI, “Sandboxing Implementation,” openai/codex, GitHub, 2026. https://deepwiki.com/openai/codex/5.6-sandboxing-implementation ↩ ↩2 ↩3
-
OpenAI, “Inside the Codex Sandbox: Platform-Specific Implementation on macOS, Linux and Windows,” Codex Knowledge Base, April 2026. https://codex.danielvaughan.com/2026/04/08/codex-sandbox-platform-implementation/ ↩ ↩2 ↩3
-
OpenAI, “Agent Approvals & Security,” ChatGPT Learn, 2026. https://developers.openai.com/codex/agent-approvals-security ↩ ↩2 ↩3 ↩4
-
OpenAI, “Auto-Review of Agent Actions,” ChatGPT Learn, 2026. https://developers.openai.com/codex/concepts/sandboxing/auto-review ↩ ↩2
-
Pierce Freeman, “A Deep Dive on Agent Sandboxes,” pierce.dev, 2026. https://pierce.dev/notes/a-deep-dive-on-agent-sandboxes ↩