A few years ago you could almost guess the first page of an audit report before opening the repo. A reentrancy here, a missing onlyOwner there, a token transfer whose return value nobody checked.

That's not really true anymore. Most developers now write code with an AI assistant open in the next tab, and that assistant has read more audited code than any of us ever will. Plenty of AI security scanners are free and one command away.

So founders ask us a fair question: if AI writes the code and AI checks the code, why pay people to read it?

We use AI in our own work every day. We also spend our days reading code that AI helped write, so we have a pretty good idea of where it stops being enough.

Yes, AI-written code is safer

If you think code written with AI help has fewer of the classic bugs than what people wrote a few years ago, you're right. We see it in our audits too.

Assistants rarely forget a reentrancy guard. They use SafeERC20 without being asked. They know an upgradeable contract's initialize() needs the initializer modifier, and that the implementation's constructor should call _disableInitializers(). The textbook bugs that used to fill the first page of every report show up a lot less often.

That's good news for everyone. It also means the bugs that are left are the ones that were always the hardest to find, and the most expensive to miss.

So where are the bugs now?

AI is very good at writing exactly what you asked for. It has no opinion on whether what you asked for is a good idea.

Here's a pattern that shows up in reward contracts all the time:

// Anyone can top up the rewards. Generous, right?
function notifyRewardAmount(uint256 reward) external updateReward(address(0)) {
    if (block.timestamp >= periodFinish) {
        rewardRate = reward / DURATION;
    } else {
        uint256 leftover = (periodFinish - block.timestamp) * rewardRate;
        rewardRate = (reward + leftover) / DURATION;
    }

    lastUpdateTime = block.timestamp;
    periodFinish = block.timestamp + DURATION;

    rewardToken.safeTransferFrom(msg.sender, address(this), reward);
}

Safe transfer, check. Rewards updated before the rate changes, check. State written before the external call, check. A static analyzer might grumble about block.timestamp and move on.

Now imagine someone calls it with 1 wei. Whatever rewards are left get spread over a brand-new full DURATION, so the rate drops and the end date moves. Do that once a day, and by the time your 7-day program was supposed to end, about a third of the rewards still haven't been paid out, stakers are earning about a third of the rate you promised, and the program now ends next week. Tomorrow it will end next week too. The attacker pays some gas and seven wei, and doesn't make a cent. Griefing doesn't need a business model.

One 1-wei call a day, and the program never ends
Share of a 7-day reward program still unpaid, by day
Unpaid rewards over time, with and without the 1-wei griefing call Without the attack, rewards are fully paid by day 7. With one 1-wei call per day, 34% is still unpaid on day 7 and 12% on day 14. 0% 25% 50% 75% 100% 0 2 4 6 8 10 12 14 days since the program started planned end as planned 34% still unpaid 12% on day 14
Each call re-spreads what's left over a fresh 7 days, so every day only 1/7 of the remainder gets paid out. Unpaid share after n days = (6/7)n.

Not a single line in that function is wrong. The bug is a design decision: letting anyone call it. The fix is boring (restrict who can call it, or don't restart the period on top-ups). Spotting it is the hard part.

To be fair, a good AI scanner might catch this one, because it's a known pattern that appears in plenty of public audit reports. The bugs that get through are the ones specific to your protocol, the ones nobody has written a report about yet. They tend to look like this:

  • business logic where the code does exactly what it says, and what it says is wrong
  • integrations, where your vault, an oracle and a lending market are each fine alone and broken together
  • economics: flash loans, rounding someone can farm, liquidations at the edges
  • assumptions nobody wrote down, like “this token has 18 decimals” or “only the keeper will ever call this”
Bug classAI assistants & scannersWhy
Reentrancy, unchecked transfers, missing modifiersUsually caughtThousands of public examples to learn from
Uninitialized proxies, known library misuseUsually caughtWell-documented patterns with standard fixes
Known griefing patterns, like the one aboveSometimesCaught if it looks enough like a public report
Business logic specific to your protocolRarelyThe tool doesn't know what the code is supposed to do
Integrations across protocolsRarelyNeeds the other protocol's behavior in your head too
Economic attacks (flash loans, rounding, liquidations)RarelyExploitability depends on prices, liquidity and profit
Unwritten assumptionsRarelyYou can't flag a rule nobody wrote down

Your AI assistant is a very fast junior developer with perfect recall and zero paranoia. Security is mostly paranoia.

What your AI security tool actually gives you

A lot of teams run AI security tools now, and some build their own. Good. We've built security tooling ourselves, so we know what it's good at: producing a list.

For every item on that list, somebody still has to work out whether it's real or the 40th “consider emitting an event”, and whether anyone can actually exploit it, at what cost and for what profit. Then there's everything the tool didn't report, which is the part people forget. A clean scan means the tool didn't find anything it knows how to look for. It's a smoke detector that only knows about toast.

One habit that helps a lot: turn findings into tests. For every finding you think is real, write a test that proves it. If you can't, either it's a false positive or you don't understand that part of your own code yet. Both are worth knowing before mainnet.

And do use the tools. They're great for writing tests and fuzz harnesses, explaining unfamiliar code and catching silly mistakes before you commit. You'll also get more out of an AI assistant if you ask it better questions:

Instead of askingAsk
“Is this code secure?”“List every assumption this function makes about its inputs and callers.”
“Find bugs in this contract.”“Write invariant tests for these three properties.”
“Is this safe from attacks?”“How would you attack this function with a flash loan?”

The first column gets you a polite list of generic advice. The second gets you something you can actually use.

We use AI to get through codebases faster, so our researchers spend more of their time on the parts that need a human. Just don't mistake a scan for a review.

Why you want several researchers

When you audit with Valves, you get several researchers, and each one brings their own tools, their own idea of what “secure” means and their own way of working through a codebase. One follows the money. One goes straight for access control. One opens the math library and doesn't come out for two days.

That's on purpose, because different people find different bugs. If you've ever looked at the results of a public audit contest, you've seen it: the best researchers on the same codebase rarely hand in the same list. A tool looks at your code one way, and you want as many different eyes as you can get on your side before launch.

When should you audit?

Timing matters almost as much as the audit itself. Too early and you're paying to review code that won't ship. Too late and the fixes collide with your launch date.

Here's the order that works:

  1. YouFinish development. Feature-complete, not “basically done, just one more thing.”
  2. YouRun the free tools, like Slither or Aderyn for Solidity, plus whichever AI scanner you like.
  3. YouFix what they find. Paying auditors to rediscover what a free scanner already told you is an expensive hobby.
  4. YouDeploy on testnet and use the protocol like a real user would. You'll find things.
  5. YouFine-tune, then freeze a commit. One hash, and no more changes to the code in scope.
  6. UsHand it to us. We review that commit, report every finding with its severity, impact and a recommended fix, and stay in a shared channel with your developers the whole time.
  7. You + UsFix the findings and send them back for fix review. We check that each fix actually works and didn't break something else.
  8. YouDeploy exactly the commit we reviewed, verify the source code and set up a bug bounty. The audit covers one commit. Attackers get every block after it.

None of it is rocket science, but skipping steps is how protocols end up on rekt.news. We wrote a full checklist for steps 1 to 5: How to Prepare for a Smart Contract Audit.

Before you launch

Use AI to build faster and the free tools to sweep up the obvious stuff. Then, before real people put real money in, let someone whose whole job is breaking protocols have a go at yours. Better us than someone with a fresh wallet and a flash loan.

Getting close to launch? Tell us what you're building and we'll come back with a plan and a quote.