We pointed our audit agent at our own governance mesh
flux7-mesh governs what AI agents are allowed to do. So we aimed our RAG-powered audit agent at the mesh's own source code and asked it the uncomfortable question: how would an agent escape this? It found eight ways. Here is what self-auditing a governance tool teaches about agent security.
A governance tool that can be bypassed is theatre. You can write the cleanest policy engine in the world, but if an agent can quietly hand itself the keys, the policy is decoration. So before claiming flux7-mesh governs anything, the honest move was to attack it.
We had the right adversary already in the stack. audit7 is a RAG-powered audit agent: it reads source code, queries a knowledge base (here, the OWASP LLM and Agentic corpora), and writes findings. Crucially, audit7 runs through the mesh and stores its findings in our governed memory. So the setup was a small ouroboros: the agent that audits, governed by the thing it audits, remembering across sessions.
We aimed it at flux7-mesh's own Go source, scope: security. It found eight issues. Two were critical. The interesting part was not the count, it was their shape.
The guard that forgot to guard itself
The mesh's whole premise is that some actions require a human to approve them. You write a policy that says filesystem.write_file → human_approval, and the agent's write blocks until a person says yes.
The first critical finding: a virtual tool called grant.create let an agent mint itself a temporary grant — a sudo token that bypasses human_approval. And grant.create was dispatched before the policy engine ran. So a constrained agent could, in two calls, grant itself everything and then do the thing it was never allowed to do. The lock was fine. The keyring was sitting on the counter.
We fixed it: minting a grant is now an operator action, reserved to declared supervisor agents. Felt complete. It wasn't.
Look for the twin
We ran audit7 a second time, on the patched code. The first eight findings were gone. But the deeper pass surfaced something we had missed the first time, and it is the single most useful lesson of the whole exercise.
There is a second door into the same room. Where grant.create lets an agent avoid the approval, approval.resolve lets it satisfy the approval — by approving its own pending request. Same outcome, the human-in-the-loop defeated, reached from the other side. In the default mode, any agent could call it.
We had hardened one privileged primitive and left its mirror image wide open, because we fixed the bug we were shown instead of the class of bug. The takeaway: when you guard a privileged operation, immediately look for its twin. Anything that can reach a protected state has siblings that reach the same state differently. Both grant and approval mutation are now gated identically, through one shared check.
This is why a second audit pass matters more than a thorough first one. The first pass finds bugs. The second pass, run on your own fixes, finds the assumptions your fixes encoded.
The other six
The rest mapped cleanly onto the OWASP agentic threat model, and each is worth naming because they recur in any agent system that touches a network:
Identity spoofing past authentication. A legacy Bearer agent:<name> header was checked before JWT validation, so it worked even with JWT configured — making the cryptographic identity check decorative. An agent could simply claim to be a more privileged one. Now, with JWT on, plaintext identity claims are rejected by default.
Injection slipping through the busy door. The check that blocks auto-approval when a tool call's parameters smell of prompt injection lived only on the HTTP path. The MCP path — the one Claude Code and Cursor actually use — had none. The highest-traffic, most-exposed codepath was the unguarded one. The guard now lives in a single function both paths call, so they cannot drift apart again.
SSRF, twice. Agent-supplied callback URLs and operator-supplied OpenAPI spec URLs were fetched without protection. That is a server-side request forgery primitive: make the mesh fetch 169.254.169.254 and it hands back cloud credentials. The naive defenses (resolve, check the first IP, then fetch) are bypassable by DNS rebinding. The fix checks every resolved address at dial time, so the IP that passed the check is the IP actually contacted.
Resource exhaustion. The rate limiter's per-agent map grew forever — and agent IDs are self-declared, so an attacker could enumerate millions of them until the process died, taking governance down for everyone. Now the map evicts idle agents and has a hard cap.
One finding turned out to be a false positive — the audit claimed CLI subcommands escaped per-command policy, but reading the code showed the policy is evaluated on the real command name on both paths. Worth stating plainly: an LLM audit produces leads, not verdicts. You verify each against the code before you believe it. That discipline is part of the method, not an afterthought.
The pattern under every fix
Seven of the eight were real, and every single fix took the same shape. It is the most portable thing we learned, so it deserves to be stated as a rule:
A safe, explicit default, plus an opt-in escape hatch.
The control plane is loopback-only until you set an admin token. Identity is JWT-strict until you explicitly allow the legacy form. Transport is plaintext with a startup warning until you point it at a certificate. The data plane is anonymous-but-policy-governed until you require authentication. In every case the default never silently exposes anything, and the capability is there for the deployment that genuinely needs it.
The opposite failure mode — a permissive default with a "remember to lock this down" note in the docs — is how most agent systems leak. The note is never read. The default is what ships.
Why this is the demo that matters
"Agent governance" is easy to claim and hard to show. A slide that says "policy enforcement, human approval, full audit trail" proves nothing. What proves something is pointing an adversarial agent at your own enforcement layer, on stage, and showing both the holes it finds and that the enforcement still failed closed while it probed.
When audit7's first run hit the mesh before its policy was loaded correctly, every tool call came back denied — and the agent refused to fabricate findings, reporting the lockdown instead. That is the system working: fail closed, and an agent that cannot act simply cannot act. The most convincing security demo is not the absence of holes. It is watching the guard hold while something actively tries the doors.
The mechanisms, the threat model, and a production hardening checklist live in the Agent Security docs. flux7-mesh is open source: github.com/KTCrisis/flux7-mesh.
Disclosure: the security review was performed by audit7, an AI audit agent; every finding was verified against the source before being fixed, and one was rejected as a false positive.