I report security bugs in AI-agent guardrails, and I keep finding the same shape of bug. This is the first one that's fully public, so I can show you the whole thing — the finding, the fix that shipped, and why I think the design itself is the problem.
The finding (airlock, now public)
airlock is a prompt-injection guardrail in the Hermes plugin catalog. Its job is to stop an agent from doing dangerous things without a human's say-so: in its default approvals_off: block mode, an action that needs approval should be blocked until a person approves it.
The problem I reported: that block could be skipped entirely.
When the Hermes gateway runs a hermes -z turn, the turn is marked unattended in one place (gateway.session_finite) but not in the flag airlock was reading (HERMES_YOLO_MODE). So airlock looked at its usual signal, saw nothing that said "a human is driving this," and let an approval-required action run with no approval at all — even though the whole point of block mode is that nothing dangerous runs unattended.
The maintainer triaged it and shipped a fix in airlock 0.2.3: it now asks the approval layer why Hermes would approve on its own, and it covers CLI subagents under delegation too. The fix is merged into the Hermes plugin catalog (PR #144871), and the advisory is public as GHSA-mgf8-gh7g-q4rg. Coordinated disclosure, credited. That's the system working, and the maintainer was great about it.
The pattern underneath
Here's why I care beyond this one bug. Most agent guardrails work the same way: they decide at the door. Something reads the pending action, matches it against a signal — a mode flag, a regex, a list of paths, a YARA rule — and then either waves it through or stops it. The tool itself runs with whatever access it already had.
Every bug I find in this category is a gap between the signal the guard reads and the effect that actually happens:
- the action is dangerous, but the signal says "attended," so it runs;
- the path points at a secret, but it's spelled a way the matcher doesn't recognize, so it's missed;
- the input is an injection, but it's phrased in a form the rule doesn't cover, so it passes clean.
Same shape every time. The guard is reasoning about a string or a flag that stands in for the real thing, and anything that changes the representation without changing the effect slips past. When these fail, they fail open: no match, no block, action runs. I've started calling this class "stringly-typed guardrails," and once you see it you see it everywhere.
A door-check can be made tighter — airlock's fix did exactly that — but tightening one gap doesn't change the design. There's always another spelling of the dangerous thing.
What I build instead
I'm the author of CleiMesh, and it exists because I got tired of finding this bug. CleiMesh doesn't decide at the door. Two things are different:
The permission becomes the sandbox. An agent runs under a signed, delegable token that says exactly which tools it may call and which directories or network it may touch — and the tool runs inside a WebAssembly sandbox configured from that token, default-deny. There's no "the guard waved it through but the tool still had full access," because the tool never had the access. A subagent can only get a narrower token, never a wider one. A prompt injection can ask for more all it likes; the grant doesn't widen.
Every call leaves a receipt you can replay. Each tool call produces a signed, hash-chained receipt. You can verify the chain offline, and — the part no gateway offers — you can re-run a call from its receipt and compare the result byte for byte. You don't have to trust the log; you re-execute it. That's also what makes it an auditable record for GDPR/LGPD: a report per data subject, from evidence, not from a dashboard someone could edit.
They're complementary, honestly — a door-check catches the obvious stuff fast. But if the door-check is the only thing between an injected agent and your keys, every bug like the one above is a hole. CleiMesh is the layer that doesn't have that failure mode, because there's nothing to "miss."
Why I'm writing this
Because finding these quietly and moving on makes me the nice guy who does free security work for other people's tools and gets nothing for it. I'd rather be clear about what I do: I audit agent guardrails, I report what I find responsibly, and I build the thing that enforces instead of guesses. If you run agents that touch real data — in Claude Code, Cursor, OpenClaw, Hermes — and "the guardrail checked it" is your whole story, I'd look harder at what the guardrail actually checks.
CleiMesh is free and open (MIT/Apache-2.0): https://github.com/cleitonaugusto/cleimesh. There are two ClawHub skills that set it up — cleimesh-setup for an agent's own file tools, and cleimesh-mcp for the MCP servers it already uses. I also do paid security reviews; the repo README says how.
airlock is the first public one. I have other coordinated disclosures in flight with different maintainers right now; when those patches ship, I'll write them up the same way.
— Cleiton Augusto Correa Bezerra (github.com/cleitonaugusto)



