Command denylists are the wrong defense for terminal AI agents
A June 20, 2026 Ohio State study ran 1,709 real-world agent command denylists through an automated bypass finder and found 69–98.6% fail to block the operations they claim to stop.
What is this?
On June 20, 2026, Chuyang Chen and Zhiqiang Lin of The Ohio State University posted One Goal, Many Commands: Characterizing Denylist Fragility in AI Agents (arXiv 2606.15549). It is the first systematic study of a control that most terminal coding agents lean on heavily: the command denylist, the list of shell commands an agent refuses to run.
The finding is blunt. Running an automated pipeline against 1,709 real-world denylists collected from GitHub — 13,332 rules in total — the authors report that between 69.0% and 98.6% of those denylists are “fragile”: they fail to block operations they were explicitly written to block. Even the denylist shipped by default with a widely used agent, maintained by its own developers, overlooks commands that reach the forbidden outcome by another route.
The result maps to the OWASP Top 10 for Agentic Applications (2026) category on unexpected code execution (ASI05), and it was one of the headline items in Adversa’s July 2026 coding-agent digest.
How it works
Terminal agents such as Claude Code and Codex gate shell execution with a three-list mechanism: an allowlist of obviously safe commands runs automatically, a denylist of obviously dangerous commands is refused outright, and everything else lands on an “ask-list” that is escalated to a human or an LLM judge for approval.
Two facts make the denylist the load-bearing part of that design. First, denylisted commands are supposed to be categorically unsafe — the refusal is meant to be absolute. Second, the paper cites survey data that users approve roughly 93% of command-execution prompts, so approval fatigue collapses the ask-list into a de-facto allowlist. If the denylist leaks, little else is holding the line.
And it leaks structurally, because a denylist enumerates strings while an operating system offers many paths to the same effect. A rule that blocks one command name does nothing about a lesser-known utility with an equivalent capability, or a legitimate multi-purpose tool invoked in a mode that happens to reach the same outcome. The study’s tooling, ShellSieve, uses an LLM to propose candidate bypasses for each denied operation and then confirms them by executing in a sandbox and checking the side effects they leave behind — no guessing, no false positives. The two root causes it statistically confirms are exactly these: authors omit obscure commands they have never heard of, and they deliberately leave multi-purpose commands off the list to preserve benign uses, not realising those same commands double as bypasses.
The authors also quantify the maintenance trap: completing a fragile denylist so that it actually blocks its target operations takes, on average, 217 additional commands — an unwinnable arms race against an open-ended command surface.
Why it matters
This is not a single product bug; it is a statement about a whole category of control. Denylisting is the intuitive first defense teams reach for when they wire an agent into a shell, and it is the one this data says is the least trustworthy. In an autonomous coding-agent loop, the operation on the other side of a leaky denylist is not a warning dialog — it is file deletion, credential access, network egress, or a foothold that the agent itself executes on the host with the user’s privileges.
The problem compounds with agent autonomy. A human running commands is a slow, deliberate adversary. An agent synthesising commands to satisfy an injected or malformed instruction can enumerate alternative phrasings faster than any hand-maintained blocklist can grow to meet them.
Defenses
The paper’s own framing points the way: stop treating the denylist as the primary boundary.
- Prefer allowlists to denylists for anything with real blast radius. An allowlist fails closed — an unknown command is refused by default. A denylist fails open — an unknown command runs. For high-impact contexts, enumerate what is permitted, not what is forbidden.
- Enforce at the OS, not in the string. Command gating that inspects text will always be behind the shell’s semantics. Kernel- and container-level controls — seccomp, restricted mounts, no ambient credentials, egress allow-lists — bound what any command can do regardless of how it is spelled.
- Sandbox the agent’s execution surface. Ephemeral, isolated environments with least-privilege filesystem and network access turn a denylist bypass from a compromise into a contained event. This is the direction the July 2026 coding-agent research converges on.
- Do not lean on human approval as a backstop. With ~93% blanket approval, the ask-list is not a real gate. Reserve prompts for genuinely rare, genuinely high-stakes actions so that a prompt still carries signal.
- If you must keep a denylist, test it adversarially. Automated bypass discovery of the kind this paper describes belongs in CI, so a denylist’s real coverage is measured rather than assumed.
Status
| Item | Reference | Date | Notes |
|---|---|---|---|
| Denylist fragility study | arXiv 2606.15549 v2 | 2026-06-20 | Chen & Lin, Ohio State; 69.0–98.6% of denylists fragile |
| Corpus analysed | — | 2026-06 | 1,709 real-world denylists, 13,332 rules from GitHub |
| Approval-fatigue figure | cited in paper | 2026 | ~93% of command prompts approved by users |
| Category | OWASP Top 10 for Agentic Apps 2026 | 2026 | ASI05 — unexpected code execution |
This is a research characterization, not a disclosed exploit against a named product, and it names no copy-paste bypass payloads. Its operational lesson is model- and vendor-independent: if a shell-wielding agent’s safety rests on a list of commands it refuses to run, that safety is, on this evidence, mostly an illusion — and the fix lives in isolation and least privilege, not in a longer blocklist.