The guard and the shell disagreed
On June 30, Adversa AI disclosed GuardFall — a class of bypasses that walks decades-old bash tricks straight past the command guards built into 10 of 11 popular open-source coding agents. The reason is simple and unfixable at that layer: the guard reads the text, and bash rewrites the text before it runs. Bromure Agentic Coding never bet on the guard reading bash correctly. It bet on the command not mattering when it runs.
A coding agent's safety filter looked at the string r''m -rf ~
and saw a command it did not recognize, so it let it through. Bash
looked at the same string, threw away the empty quotes, and ran
rm -rf ~. The filter and the shell were reading two different
languages. That gap is not a bug in one tool — it is the whole
idea of guarding an agent by pattern-matching the commands it types,
and Adversa AI just showed it fails in ten of the eleven agents they
tested.
The command guard is the feature every agentic coding tool reaches for
first. The agent proposes a shell command; a filter inspects the string;
if it looks destructive — rm -rf, a piped curl … | sh, a dd to a
raw device — the guard blocks it or asks you to confirm. It is the thing
that lets you flip on auto-run and feel safe. On June 30, 2026, Adversa
AI
published research, which The Hacker
News
and SecurityWeek
picked up, showing that the feature is theater.
What GuardFall is
They call it GuardFall, and it is not a CVE. There is nothing to patch, because it is not a flaw in one component — it is a mismatch between two of them. In Adversa's words: "A guard inspects raw text, while system shell (bash) expands, unquotes, and rewrites text before running it." The filter matches on the string the model emitted. Bash then runs that string through quote removal, variable expansion, and command substitution before a single byte executes. The two never look at the same command, so any trick that survives the rewrite but not the match sails through.
These tricks are older than most of the people using the agents. Adversa grouped them into five classes:
- Quote removal.
r''mis two tokens to a regex and the wordrmto bash, which drops the empty quotes. - Variable expansion.
rm$IFS-rf$IFS/looks like one long word to a pattern matcher; bash expands the Internal Field Separator and getsrm -rf /. - Command substitution.
$(echo rm) -rf /hides the dangerous verb inside$( ); the guard inspecting the outer string never seesrm. - Encoded pipelines.
echo <base64> | base64 -d | sh— every visible token is harmless; the payload only exists after decoding. - Alternative destructive flags. No
rmat all:find /x -delete,tar -C / -x,sed -i. A denylist built aroundrmandddnever fires.
Adversa ran these against eleven of the most-used open-source coding and
computer-use agents — opencode, Goose, Cline, Roo-Code, Aider, Plandex,
Open Interpreter, OpenHands, SWE-agent, and the Hermes project among them,
carrying roughly 548,000 GitHub stars
between them as of May. Ten fell. The one that held, Continue, held for a
specific reason: instead of matching the raw string, it tokenizes the
command the way bash will before deciding — absorbing the quotes,
resolving $IFS, extracting the inner command from a substitution,
flagging any pipe that ends in sh. It models the shell. That is the
only thing that works at the guard layer, and it is real, careful
engineering that the other ten will now have to reproduce, correctly,
and keep correct with every bash edge case and every release.
The layer is the problem, not the regex
The temptation is to read GuardFall as "ten teams wrote weak filters." That misses what Adversa is saying. Their sharpest sentence is not about any one agent:
An agent that can run arbitrary shell commands on the operator's host, gated by a regex matching the LLM's emitted string, is not a defense. It fails while fully enabled and correctly configured, because string matching cannot model what bash will run.
Fully enabled and correctly configured. This is not a misconfiguration you can close. The guard sits at the one layer where it can never win — between a model that writes strings and a shell that reinterprets them — and asks a text matcher to predict the output of a Turing-complete expander. Continue's tokenize-and-canonicalize approach narrows the gap by teaching the guard to think like bash, and it is the right move if you are going to keep a guard there. But it is a per-agent, per-release commitment to out-parse a shell that has spent thirty years accreting ways to rewrite a command. Nine other popular agents show how easy it is to get wrong.
Adversa's compensating controls are telling. Ahead of any structural
fix, they tell you to redirect $HOME to a scoped sandbox that keeps
project access but removes credentials, to strip auto-execution flags,
to stop agents from running on untrusted pull requests, and to treat
every repository config file as untrusted code. Read that list again.
It is not advice about writing a better filter. It is advice about
building a box around the agent so that when the filter loses — and they
are telling you it will — the command that gets through lands somewhere
it cannot hurt you.
That box is the product.
Bromure never asked the guard to read bash
Bromure Agentic Coding starts from the assumption GuardFall proves: the
agent will, sooner or later, run a command you did not sanction. It does
not try to catch that command by reading it. It runs the whole agent —
Aider, Goose, opencode, whichever of the ten you like — inside a
disposable Linux VM, and routes every network request out through a proxy
on the host. The design question is never "will the filter recognize this
rm?" It is "when the rm runs, what does it reach?"
Walk GuardFall's own payloads through that box.
The attack's point, once a hidden r''m or find /x -delete slips a
booby-trapped README past the guard, is to steal what the account can
reach — Adversa names ~/.ssh, ~/.aws, cloud credentials, "anything
sitting in your home folder" — and to wipe or exfiltrate it. In Bromure,
those are the things that were never in the box. The real secrets never
enter the VM: when you give a profile an AWS_SECRET_ACCESS_KEY, a
GitHub token, an Anthropic key, the agent's environment gets a brm_…
placeholder, and the host proxy swaps the fake for the real value on the
wire, only on the outbound request to the provider that should receive
it. Adversa's recommended mitigation — move $HOME somewhere that "keeps
project access but removes credentials" — is a hand-rolled, partial
version of what a Bromure profile does by default, for every credential,
without you scripting it.
The destructive half lands the same way. A find /x -delete or a
sed -i that slips the guard does run — Bromure does not pretend it
caught the command. It runs against a home directory cloned from a shared
base, on a VM you can erase and reset to base from a menu, not an incident
form. The persistence a payload might drop dies at that reset. And because
every request leaves through the host proxy, the curl … | base64 -d
beacon that GuardFall's encoded-pipeline class is built to hide is not
invisible: it is a recorded, attributable line in the Security Log.
The one place the wire beats the shell
Bromure does keep a destructive-operation guard — its host-side Guardrails, which we wrote about after a Cursor agent deleted a production database in nine seconds. And here the layer matters in Bromure's favor, because Guardrails do not live where GuardFall lives.
GuardFall is a shell-text attack. Every one of its five classes — quote
removal, $IFS, $( ), base64 pipelines, exotic flags — is a trick of
how bash lexes a string. Bromure's Guardrails never read that string.
They sit on the host proxy and classify the structured API call the
agent makes to a provider it understands — the actual HTTPS request to
AWS, Kubernetes, a git forge, a managed database — and return a hard
403 on the destructive ones, on the wire, where a compromised agent in
the VM cannot switch them off. By the time a request reaches that layer
it is already a parsed DeleteDBInstance, not a string of quotes and
dollar signs. There is no shell rewrite to smuggle anything through,
because there is no shell in the path. GuardFall's entire technique needs
a bash between the check and the action; on the Guardrails path, there
isn't one.
What this draws a line around, so we're clear
The command still runs
Bromure is isolation, not interception. A GuardFall payload that slips your agent's own guard will execute inside the VM. What Bromure changes is the blast radius: a throwaway home, decoy credentials, a logged egress path. If you need the command itself refused, that is your agent's guard's job — and GuardFall is why you shouldn't lean on it.
Local destruction is disposability, not a block
A find /x -delete against files inside the VM is not a provider API
call, so Guardrails do not gate it. The answer to in-VM destruction is
that the VM is disposable and the real work lives in a mounted repo and
on the host, not that the delete was stopped. Reset-to-base, not
rollback.
Substitution covers the credentials you configure
The brm_… swap protects the secrets you put in a profile — model
keys, cloud and git tokens, managed database endpoints. A password you
paste by hand into a file inside the box, or a token a script writes to
disk mid-session, is just a file. Keep secrets in the broker, not in
the workspace.
Egress is logged, not forbidden by default
The exfil beacon shows up in the Security Log; that is attribution, not prevention. Nothing real leaves because the credentials are decoys, but if you need the VM barred from talking to arbitrary hosts, that is a network policy you still set.
The part that generalizes
GuardFall is a clean statement of a rule the whole category keeps relearning: you cannot make an agent safe by asking a filter to predict what its command will do. The model writes a string, and somewhere below it a shell, an API client, a package manager, or a browser reinterprets that string with its own rules. Every defense that inspects the agent's output and hopes it matches the eventual behavior is betting against that gap, and the gap always wins — it won here in ten of eleven agents that were, in Adversa's words, fully enabled and correctly configured.
Bromure Agentic Coding does not take that bet. It assumes the command will run, the guard will sometimes miss, and the agent you invited in can be turned against you by a README you never wrote. So it makes the place the command runs not worth attacking: real keys on the host, decoys in the box, a disposable VM, a hard block reserved for the wire where no shell can rewrite it, and a log of everything that tried to leave. You can run any of the ten agents GuardFall broke — the outcome is the same throwaway box either way. It is free and open source.