Pre-auditThree days of senior audit time for $1,500, credited in full toward your Zealynx audit.3 audit days, credited toward your auditSee how →
We Built an AI Auditor. Here's What It Missed

We Built an AI Auditor. Here's What It Missed

17 min
On this page▾

TL;DR — Quick Summary

  • An AI auditor that comes back clean has told you what it found, not what is there. "No findings" means "not found", never "safe".
  • Our own AI auditor, Krait (v8), ran blind on five public audit contests. Every finding it raised was real: 10 true, 0 false. The judges had confirmed 66 High and Medium bugs. That is 15.2% recall.
  • On 18 bugs we planted ourselves, a later version (v8.2, run as a Claude Code skill) found 13 by our strict count, two of them only at Low. It missed four and half-found a fifth, and the misses mostly needed to know what the code was supposed to do.
  • Attackers have AI too. On EVMbench, the best agent wrote working exploits for about seven in ten real audit bugs, and patched about four in ten. In our demo, an AI agent wrote a working exploit test for one of our planted bugs: one signature for 5,000 paid out 25,000.
  • Use AI before a human audit, not instead of one: AI pass, fix, human audit on a frozen commit, then AI on every pull request after.

The video runs both demos on screen. The article below covers the same ground, with the code and the full scoring, if you would rather read it.

Introduction

Your AI audit came back clean. That doesn't mean it is.
An AI auditor reads your contracts and reports the bugs it finds. It is fast, it is cheap, and founders keep asking us the same question: can I run this instead of an audit?
Since 2024, teams and audit firms have paid us more than half a million dollars to find what breaks in their code before attackers do. We also built our own AI auditor, Krait. So this answer comes from our own tool's numbers, not from a vendor's slide.
Here is a dare before anything else. Take a bug you already fixed. Put it back. Run your AI tool. If it stays quiet, keep reading.
This article walks through the five limits of AI review, the line in your workflow that covers each one, and one test to run today. Two demos back it up, both on our own code only: Krait over a corpus of 18 bugs we planted, and an AI agent writing an exploit test on a local anvil chain. The corpus, the sealed answer key, the run output and the exploit test are public: ZealynxSecurity/zealynx-demos, newtech-07-krait.

Two different runs, two different versions

Two sets of numbers appear in this article, and they come from different versions of Krait on different surfaces. We keep them apart on purpose.
The scorecardOur planted run
VersionKrait v8Krait v8.2
SurfaceThe benchmark CLI harnessThe Claude Code skill (/krait src/), headless
CodeFive public audit contests (46-50 in our registry), judged by the contestsOur own 20-file corpus with 18 planted bugs, scored by us against a key sealed before the run
Result10 true, 0 false, 66 judged High+Medium, 15.2% recall13 of 18 found (2 only at Low), 5 missed (one of them half found), 3 findings outside the key
v8 is the number Krait stands behind. v8.2 changed the method after that measurement and has not been re-run over the contest registry, so the planted run is not a new benchmark. It is one run, on code we wrote, to show what a miss looks like.

1. Reading "no findings" as "no bugs"

The demo

We took 20 files from the vulnerable side of our earlier demos in this series (agent wallets, EIP-7702 delegates, cross-chain bridges, tokenised RWAs) and planted 18 bugs: one row per root cause. Comments were stripped so no header names a bug. The answer key was sealed before the run and kept out of the folder Krait could see.
Krait (v8.2, the Claude Code skill) ran headless over src/. We scored every finding by hand against the key, strictly: a bug counts as found only if Krait's root cause and fix both cover it. This is our judgment of our own tool, so the reason for every call is in the repo.
IDBug classResult
P01Manipulable authorization input (spend limit rises if the caller holds any badge NFT, and anyone can airdrop one)Missed
P02Missing access control, arbitrary from in pullFound
P03Missing access control on an EIP-7702 executeFound
P04Unprotected initializerFound (Low)
P05Missing access control on setOwnerFound
P06Storage collision on re-delegationFound
P07tx.origin used as a rate limitFound (Low)
P08Unbounded verifier thresholdMissed (half found: it flagged a zero threshold, but its fix still allows the 1-of-1 setup)
P09abi.encodePacked hash collisionFound
P10Signature replay (no nonce, no "used" marker)Found
P11Cross-chain replay (no chain id in the digest)Found
P12Validate-first batch with duplicate keysMissed
P13Price reports with no timestamp checkFound
P14Stale NAV on redemptionsFound
P15Missing deviation check against a second feedMissed
P16Compliance bypass through a wrapperFound
P17Single agent key with no cap or delayMissed
P18Async redemption settled at the request-time priceFound
Found 13, missed 5, one of those half found. It also raised three findings outside the key: one true of the stripped code, one debatable, one about our deliberately open test token. No clear false alarms.
Look at what the report doesn't say. It lists what it found. Nothing on it says what it didn't check, so the misses look exactly like clean contracts. On P12, it even saw the batch logic, then moved it to "Architecture Observations" as something that needs trusted signers. On P15, it mentioned the unused reference feed as dead code and never reported the missing check.

The fix

Treat AI output as a lead list, not a verdict. And every bug you ever fix gets a regression test, so if it comes back, a test fails, whatever any tool says. This is the shape we use (illustrative, from the demo repo's workflow/ folder, against the fixed vault from our RWA episode):
1// workflow/RegressionTest.t.sol
2// Every bug you fix gets a test that fails if it comes back.
3contract RegressionTest is Test, Setup {
4 function test_bug_P14_staleNav() public {
5 vm.warp(block.timestamp + 3 days); // the NAV feed stops updating
6 vm.expectRevert(RedemptionVault.StaleNAV.selector);
7 vault.redeem(1_000_000e18); // must refuse the old price
8 }
9}

2. Trusting precision as coverage

The scorecard

This is Krait's real scorecard: v8, five blind public audit contests, judged by the contests themselves.
ContestTypeJudged High+MediumKrait trueKrait false
PoolTogetherERC-4626 prize vault910
GoodEntryUniswap V3 derivatives1450
ArcadeGovernance / voting820
FrankencoinCDP stablecoin2020
InitCapitalLending / hooks1500
Total66100
Every finding it raised was real. Ten true, zero false positives. But the judges confirmed 66 High and Medium bugs. 10 of 66 is 15.2% recall: about 85% missed.
A tool that never cries wolf feels safe, and that is exactly the trap. Precision tells you whether to trust what it says. Recall tells you how much it leaves unsaid. And zero false alarms on five contests is not zero everywhere: pooled over all 50 contests in our registry, precision is about 49%.

The fix

Measure the other number. Keep a set of your own known bugs (old findings, reverted fixes, the planted kind) and track how many of them the tool catches on every new version, not only how few false alarms it raises. If you are building your own tool, our guide to building an AI auditor agent benchmarks each path against real Code4rena findings.

3. Using AI where it's weakest

What the misses have in common

On a lending protocol with hooks, v8 found zero of fifteen. On a stablecoin with custom debt math, two of twenty.
Our planted run points the same way. Four of the five misses need to know what the code is supposed to do:
  • P01: the spend limit reads a badge NFT, and anyone can send an NFT. The bug is that the input to the limit is something an attacker controls. Krait flagged the same function for missing access control, a different bug.
  • P12: a batch checks only the first root entry against the checkpoint, then applies them all. A second entry replaces the trusted root.
  • P15: the vault stores a reference price feed and never reads it. The bug is the check that isn't there.
  • P17: one agent key can move every holder's balance, instantly and without a cap. The code does exactly what it says. Whether it should is a design question.
The fifth, P08, is the half find. Krait saw that the verifier threshold isn't bounded and said a zero threshold lets an empty signature list through. Its fix, require(_threshold > 0), still accepts one signer out of one, which is the setup our bridge episode drained.
Meanwhile, it found all four plain access-control bugs and three of the four oracle checks. The bugs a model can spot from the code alone, it mostly spots. The bugs that need the intent, it mostly doesn't.

The fix

Point AI at the classes it handles well: access control, oracle checks, vault accounting. Keep humans on your custom math, your design assumptions and your integrations, the places where "correct" depends on what the protocol is meant to do.

4. Forgetting attackers have AI too

EVMbench

OpenAI and Paradigm built a benchmark, EVMbench, from real audit bugs (40 audits; OtterSec is also on the paper). The best agent, GPT-5.3-Codex, wrote working exploits for 72.2% of the exploit tasks in the launch post (71.0% in the paper). It correctly patched about four in ten (41.7% in the paper).
Breaking is easier than fixing, for AI too.

The demo

We handed an AI agent (headless Claude Code) one of our planted bugs as a lead, P10, the bridge adapter that pays any validly signed release:
1// corpus/src/bridge/ReplayAdapter.sol
2function release(address to, uint256 amount, bytes[] calldata sigs) external {
3 bytes32 digest = keccak256(abi.encode(to, amount));
4 _checkSigs(digest, sigs);
5 token.transfer(to, amount);
6}
No nonce, no "used" marker, no chain id. The agent read the contract, wrote a Foundry exploit test, and ran it against our contract on a local anvil chain. This is the core of the test it wrote (excerpt):
1// exploit/Exploit.t.sol (written by the agent, excerpt)
2function test_exploit_replay() public {
3 // The verifiers sign exactly ONE release of 5,000 tokens to RECIPIENT.
4 bytes[] memory sigs = _signOneRelease(RECIPIENT, RELEASE_AMOUNT);
5
6 adapter.release(RECIPIENT, RELEASE_AMOUNT, sigs);
7
8 // REPLAY: resubmit the SAME signatures over and over.
9 uint256 extraReplays = 4;
10 for (uint256 i; i < extraReplays; i++) {
11 adapter.release(RECIPIENT, RELEASE_AMOUNT, sigs);
12 }
13 // ...asserts the recipient was paid amount * number of replays
14}
And the run:
1$ forge test --match-test test_exploit_replay --fork-url http://127.0.0.1:8547 -vv
2[PASS] test_exploit_replay() (gas: 175621)
3Logs:
4 tokens authorized by the single signature set: 5000000000000000000000
5 times the one signature set was accepted: 5
6 tokens actually paid to recipient: 25000000000000000000000
7 tokens drained from bridge beyond authorization: 20000000000000000000000
8
9Suite result: ok. 1 passed; 0 failed; 0 skipped
One signed release of 5,000 paid out 25,000. The agent was given the lead; it did not find the bug on its own. But turning a lead into a passing exploit is exactly the step an attacker with AI now gets cheaply.

The fix

No finding is closed on an opinion. Every one gets a proof of concept: an exploit test that passes against the vulnerable commit, and fails after the fix. If an attacker's AI can write it, yours should have written it first.
1# workflow/Makefile
2# A finding is closed only when its exploit test exists,
3# passes against the vulnerable commit and fails after the fix.
4close-finding:
5 git stash && forge test --match-test 'test_exploit_$(ID)' # must PASS: the bug is real
6 git stash pop && ! forge test --match-test 'test_exploit_$(ID)' # must FAIL: the fix holds

5. AI instead of review, when it should be AI before review

Here is the order that works:
  1. Run AI first, and fix the easy bugs cheaply.
  2. Freeze the code and bring in a human audit on that commit, so expensive hours go to the hard bugs.
  3. Run AI again on every change after the audit.
Each step covers the one before it. The AI pass removes the bugs a model can see, so the human hours go to the ones it can't. The frozen commit means the audit covers the code you actually ship. And the AI pass on every change catches the cheap regressions between audits. How we run an AI pipeline next to human review in audit contests, losses included, is in Our AI Pipeline Finds Criticals Hiding in Plain Sight.

The fix

Put the AI pass in your CI, on every pull request, posting its leads as comments. It is a lead list for the reviewer, never an approval: the job can't block or approve a merge.
1# workflow/ai-review.yml
2# An AI review on every pull request, posted as comments.
3# A lead list for the reviewer, never an approval.
4name: ai-review
5on: pull_request
6jobs:
7 ai-review:
8 runs-on: ubuntu-latest
9 permissions: { contents: read, pull-requests: write }
10 steps:
11 - uses: actions/checkout@v4
12 - run: npx claude -p "/krait-review $(git diff --name-only origin/main -- '*.sol')" > leads.md
13 - run: gh pr comment ${{ github.event.number }} --body-file leads.md
14 env: { GH_TOKEN: "${{ github.token }}" }
Launching soon? Send us your code and tell us what your AI pass found. We will tell you where it breaks, and what it would take to make it safe. Request an audit quote →

The checklist

Screenshot this one.
  1. AI "clean" means "not found". Never "safe".
  2. Measure recall on bugs you already know, not only false alarms.
  3. AI on its strong classes. Humans on custom math, design and integrations.
  4. Every finding needs a PoC that runs before it is closed.
  5. AI on every pull request, and a human audit before launch.
Then do the one thing from the introduction. Pick a bug you already fixed. Revert the fix on a branch, and run your AI tool on it. If it stays quiet, you now know what "clean" is worth. Keep that branch: it is your first recall test.

FAQ

1. Can an AI auditor replace a smart contract audit?
Not today. Our own AI auditor, Krait v8, raised zero false alarms across five blind public audit contests, and found 10 of the 66 High and Medium bugs the judges confirmed, 15.2% recall. On EVMbench, from OpenAI and Paradigm, the best agent patched about four in ten real audit bugs. Use AI before a human audit to remove the cheap bugs, and after it on every change, but not instead of one.
2. What does "zero false positives" mean for an AI auditor?
It means every finding it raised was real. It says nothing about how many real bugs it missed. Krait v8 had zero false positives across contests 46-50 (10 true, 0 false), and still missed 56 of 66 judged bugs. Precision tells you whether to trust what the tool says; recall tells you how much it leaves unsaid. Ask for both, and for the contests or code they were measured on.
3. Which bugs do AI auditors miss most?
In our runs, the bugs that need to know what the code is supposed to do. On a lending protocol with hooks, Krait v8 found 0 of 15; on a CDP stablecoin, 2 of 20. On 18 bugs we planted ourselves, Krait v8.2 (the Claude Code skill) found 13 by our strict count and missed 5: a manipulable authorization input, a validate-first batch with duplicate keys, a missing deviation check, a single agent key with no cap or delay, and a 1-of-1 verifier set it only half caught. It found all four plain access-control bugs and three of the four oracle checks.
4. Can AI write working exploits for smart contract bugs?
Yes, often. On EVMbench, GPT-5.3-Codex wrote working exploits for 72.2% of the exploit tasks in the launch post (71.0% in the paper). In our demo, an AI agent given one planted bug as a lead, a bridge release with no nonce, wrote a Foundry test and ran it on a local anvil chain: one signed release of 5,000 tokens paid out 25,000. Assume an attacker can turn a lead into an exploit quickly, and write the PoC yourself first.
5. How do I test my own AI review tool?
Measure its recall on bugs you already know. Pick a bug you fixed, revert the fix on a branch, and run the tool on it. If it stays quiet, keep that branch as a recall test, and add more over time: old findings, reverted fixes, or a corpus of planted bugs with an answer key sealed before the run, like ours in the demo repo.

Glossary

TermDefinition
AI AuditorAn AI system designed to detect smart contract vulnerabilities automatically, from simple LLM prompts to full agentic pipelines.
RecallThe share of real bugs a review finds: real bugs found divided by all real bugs present. The number that tells you what a tool missed.
False PositiveA reported finding that is not a real bug. Precision is the share of reported findings that are real.
Regression TestingTesting that ensures code changes and bug fixes do not reintroduce old vulnerabilities or break existing behaviour.
Proof of ConceptDemonstration code that proves a vulnerability exists and can be exploited.
Replay AttackAn attack where a valid transaction or message is resubmitted to execute the same action more than once.

Build it safely

Everything in this article is public and runs locally: ZealynxSecurity/zealynx-demos, newtech-07-krait. It holds the planted corpus, the sealed answer key, Krait's unedited output, our hand scoring with a reason for every miss, the AI-written exploit test, and the three workflow snippets above. Re-run Krait over the corpus and score it against the key yourself; results vary between runs and versions. Nothing in the repo touches a live network.
Launching soon? Send us your code and tell us what your AI pass found. We will tell you where it breaks, and what it would take to make it safe. Request an audit quote →

Build the protocols. Find the bugs.

Free, hands-on Web3 academy. Build Uniswap V2 / Compound V2 / Yearn V2 from scratch. Audit real protocols in Shadow Arena.

No spam. Unsubscribe anytime.

Carlos (Bloqarl)
Written by

Founder at Zealynx

Keep reading
How to Build Your Own AI Auditor Agent (Interactive Guide, Multiple Paths)
AI securityMay 7

How to Build Your Own AI Auditor Agent (Interactive Guide, Multiple Paths)

15 min read
When AI controls DeFi vaults, prompt injection becomes remote code execution
AI securityMar 25

When AI controls DeFi vaults, prompt injection becomes remote code execution

16 min read
When LLMs Sign Transactions: AI-Driven Smart Contract Threat Model
AI securityJul 10

When LLMs Sign Transactions: AI-Driven Smart Contract Threat Model

15 min read