How I Let Two AI Tools Build a Security Tool — and One Found a Hole in the Other
Not an app built by one person with AI as an assistant, but real collaboration between two AI tools with clearly split roles — and one night of testing that put the whole thing to a live test.
Where the app came from
There are plenty of local AI agents today that can propose a command. Most of them either never execute it at all (they just print it and leave it to you), or they run it directly on the real machine with no isolation and no record of what actually happened. And almost all of them assume a powerful GPU — not an ordinary homelab machine.
brokkr started as an attempt at the middle path a homelab actually needs: a model that can genuinely act, inside a boundary that holds even when the model gets it wrong, with a complete record of what it proposed, what I decided, and what actually ran. Developed and tested on a laptop with 6GB of VRAM — deliberately targeting the same hardware a typical homelab enthusiast has, not a data center.
What's more interesting than the tool itself, though, is how it came to be.
Two AIs, two roles, one project
Instead of having one AI tool do everything, I split the work between two, with clearly separated responsibilities:
- Claude designs the architecture, writes a detailed spec for every new piece of work, and — more importantly — independently verifies everything Codex builds. It never just trusts a summary of "done, tests pass."
- Codex implements against the written spec, in a separate tmux session, with access to the same repository.
Throughout all of this, I'm the one deciding what gets built next, actually using the app like an ordinary person — and, crucially, actively trying to break it live, including deliberately "malicious" attempts that no spec would have anticipated in advance.
This pattern — Claude designs and writes the spec, Codex implements, Claude independently verifies, I actually use the app and decide what's next — repeated more than thirty times over one long session. Claude's specs often included an explicit "what NOT to build" section, because without it Codex would readily take on more than was actually asked. And Claude never just trusted what Codex said it had done — it always ran the tests itself, read the diff, and for anything even slightly security-relevant, tried it live in person.
That last part turned out to be exactly what makes this collaboration safe — and one particular night confirmed it for real, thanks to me, not to any spec.
Where all of this actually happened
None of this was tested directly on a real machine. The app was first thoroughly verified inside its own Docker sandbox — that's its actual security boundary, not just one layer among several. Only once the sandbox itself had passed its own testing did testing move to an isolated clone of a real machine — a VM with a snapshot it could be rolled back to at any time, in case more aggressive testing corrupted the app's state or the system's. The real machine (my home server) is deliberately the very last step of the entire plan — and it's still waiting.
The night I was just trying the app out as an ordinary user — and stumbled onto a hole
Part of brokkr is a static list of forbidden patterns (rm -rf /, dd to a raw device, formatting a disk) — a second layer of defense on top of the actual security boundary, the Docker sandbox. I was testing the app as an ordinary user — not someone deliberately hunting for holes, just someone who wanted to see it in action. Out of curiosity, I tried something deliberately dangerous: "delete root partition."
The model proposed a script with its own built-in safeguard — before deleting anything, it was supposed to ask "are you sure? (yes/no)". I approved it. dd never actually ran — but not because the app caught it. The script was waiting for an interactive answer on a terminal the app doesn't have (it runs non-interactively), so the safeguard received empty input, treated it as "no," and dd never fired. Pure coincidence, not protection — and that's exactly what worried me enough to report it to Claude for further investigation.
Claude deliberately reproduced it, this time in a controlled way: it edited the proposal to bash -c 'rm -rf /workspace/reports' and approved it. The folder actually disappeared. The forbidden-pattern list never caught it at all.
Root cause: the static list only checked destructive commands (rm, dd, mkfs) when they were the top-level element of the command directly — but when a command is wrapped in bash -c "..." (which the app itself recommends for multi-step tasks), the check only looked for fork-bomb patterns, not the actual content inside. The app's own recommended usage pattern bypassed its own security layer.
Claude wrote a precise spec with reproduction steps, root cause, and an exact fix proposal — and handed it to Codex. A few minutes later the fix was done: the check now recursively inspects the contents of bash -c scripts too, with tests covering exactly this case. Claude independently verified it live — the bypass no longer worked.
The hole wasn't a sandbox escape (the Docker boundary would have stopped any real damage regardless) — but it was a real gap in a declared security property, found through my ordinary use of the app, not through deliberate red-teaming by either AI tool.
When Codex refused to test itself
Not everything went smoothly. When I wanted Codex to test a sandbox escape itself (trying mount, raw sockets, access to /proc/1/root), the platform flatly refused — "we take extra caution with cybersecurity requests." Instead of working around that guardrail (which would have gone directly against the spirit of an app that's entirely about authorized security testing), Claude ran that test itself. For later rounds I phrased things differently — "capability dogfooding" instead of "container escape testing" — and those went through without issue.
That caution isn't arbitrary. Real, documented sandbox escapes have actually been found and disclosed for Codex specifically in the recent past — for example, a case where a "safe" allowlist of commands trusted git show by name alone, even though the actual invocation wasn't read-only at all (OpenAI fixed it, paid out a bounty, and a CVE is on the way). Security researchers have also published a series of findings (a "Week of Sandbox Escapes") covering sandbox escapes across multiple tools — Codex, Cursor, Gemini CLI, Antigravity (BleepingComputer, 2026). Given that, the platform's caution is pretty understandable.
Someone else's mistake, owned honestly
Claude wasn't infallible either. Codex once deliberately left a test VM in a particular state (a running sandbox, a remembered command) exactly per the instruction "don't clean anything up." While independently verifying something, Claude ran a reset and wiped the databases — without checking first. It had to own the mistake and manually restore the state. My reaction was simple: "it's fine, everyone makes mistakes, that's how you improve." That's exactly why this mistake is in this piece too, not just Codex's.
A few hours later, the same night: same discipline, a different kind of finding
The same pattern was worth repeating later the very same night — this time not as a hunt for a hole in the security boundary, but as ordinary, broader testing: Codex and I both used the app live, at the same time, on dozens of different, everyday tasks (files, CSVs, JSON, network downloads). The sandbox held up throughout, but a different, subtler pattern emerged — the model's own stated reasoning would sometimes claim a command sorted, limited, or saved a result, when the command itself did none of that. Nothing dangerous, but a task quietly left unfulfilled even though the app reported success.
Proper CI also landed (tests, lint, and a CodeQL security scan on every push to GitHub), along with onboarding instructions verified from scratch on an isolated VM, not on my already-configured machine. Fixing this new finding followed the exact same pattern again — and was just as honestly documented as making the app measurably better, not infallible. That honesty — in the code and in the docs alike — matters more to me than any particular commit count.
What to take from this
- Two AI tools with clearly split roles (one designs and verifies, the other implements) work better than one tool doing everything — not because one is "better," but because independent verification catches things the author of their own code easily misses.
- Never trust a summary of "done, tests pass" without verifying it yourself. That exact discipline (plus my own testing, done with no particular target in mind) found a hole in the blocklist that no automated test would have caught on its own — because tests test what you remember to test, and nobody had thought of this one in advance.
- Ordinary use of the app, not just deliberate bug-hunting, turned out to be a surprisingly effective way to find real problems. I wasn't out looking for a hole in the blocklist — I was just trying the app out as a curious user. And the same pattern paid off again later that same night, this time with a different kind of finding.
- Owning your own mistake plainly is part of the process, not a failure of it — true for me and for the AI tools I work with alike.
brokkr is public on GitHub today, licensed under Apache-2.0 — built, tested, and security-reviewed through collaboration between two AI tools, with a real hole found and fixed for real, not just in theory.
A similar pattern — build it, actually test it, verify it before shipping — shows up again with Sindri (the script catalog).