I come from web app security and bug bounty hunting. Smart contracts are new to me, so I read a few audit guides and tried to boil them down to a routine I could actually follow.
This is that routine. It's a learning guide, not a pro's playbook. If you audit contracts for a living and I got something wrong, tell me in the comments.
1. Read the docs before the code
Every guide I read says the same thing first: understand what the protocol is supposed to do. Then bugs show up as places where the code does something else.
Cyfrin's guide puts it well: the more you know about what a protocol should do, the easier it is to notice when it does something different. Sounds obvious. It's also the step people skip when they open 10,000 lines of Solidity.
2. Run it and look at the tests
Clone the repo, compile it, call the main functions. Then open the tests and see what they cover. If you use Foundry, forge coverage shows which parts have tests and which don't. The parts nobody tested are a good place to look first.
3. Check the Solidity version
Check the pragma. Each compiler version has its own known bugs, and the version tells you a bit about how old the code is. One thing to know: since 0.8, arithmetic reverts on overflow by default. The Solidity docs say you can turn that off with unchecked { ... }, so any unchecked block deserves a second look.
4. Map the risky spots
Cyfrin lists what to hunt for first: roles, access controls, function parameters, public and external functions, payable functions, state changes, and dependencies.
Coming from web security this clicks. It's the same idea as listing endpoints, checking who can call them, and noting which ones move money.
5. Run a static analyzer, but don't trust it blindly
Slither is a free static analyzer for Solidity. Install is one line:
python3 -m pip install slither-analyzer
slither .
It runs a bunch of detectors. Some I'd want to see for any contract: reentrancy-eth, tx-origin, arbitrary-send-eth, unprotected-upgrade. It also has printers like human-summary and contract-summary that give you a quick overview of a codebase.
The guides agree on how to treat the output. It points you at weak spots. It doesn't replace reading the code.
6. Read it line by line
This is the slow part. For each function, ask what it's meant to do, who can call it, and what it changes.
Here's a small example. This contract lets people deposit ETH and withdraw it. I compiled it with solc 0.8.26 and it builds fine:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Vault {
mapping(address => uint256) public balances;
function deposit() external payable {
balances[msg.sender] += msg.value;
}
function withdraw() external {
uint256 amount = balances[msg.sender];
require(amount > 0, "nothing to withdraw");
(bool ok, ) = msg.sender.call{value: amount}("");
require(ok, "send failed");
balances[msg.sender] = 0;
}
}
Look at the order in withdraw. It sends the ETH first and sets the balance to zero after. If msg.sender is a contract, its receive function runs during that call, and it can call withdraw again before the balance is cleared. That's reentrancy.
The Solidity docs recommend the Checks-Effects-Interactions pattern: do your checks, update your state, and only then talk to other contracts. The fix is to move one line:
function withdraw() external {
uint256 amount = balances[msg.sender];
require(amount > 0, "nothing to withdraw");
balances[msg.sender] = 0;
(bool ok, ) = msg.sender.call{value: amount}("");
require(ok, "send failed");
}
One more point from the docs that I didn't know: reentrancy isn't only about sending ether. Any call to another contract can hand control over.
7. Know what usually goes wrong
OWASP has a Smart Contract Top 10 for 2026. The list, in order: access control, business logic, price oracle manipulation, flash loan attacks, missing input validation, unchecked external calls, arithmetic errors, reentrancy, integer overflow and underflow, proxy and upgrade bugs. OWASP notes the ordering is built from 2025 incident and survey data.
Interesting to me that access control and business logic come before reentrancy. That matches how it feels in web apps, where broken access control beats clever exploits.
8. Write it up
A finding that nobody understands doesn't get fixed. The guides say to show a proof of concept, give the bug a clear title, and explain the impact.
Where I'd practice
Cyfrin points to CodeHawks First Flights as a way to practice on real code, and to Solodit, a database of past findings you can read for similar protocols.
Sources
- OWASP Smart Contract Top 10 (2026): https://scs.owasp.org/sctop10/
- Solidity docs, security considerations: https://docs.soliditylang.org/en/latest/security-considerations.html
- Cyfrin, 10 steps to approach a smart contract audit: https://www.cyfrin.io/blog/10-steps-to-systematically-approach-a-smart-contract-audit
- Slither (Trail of Bits / crytic): https://github.com/crytic/slither
- ethereum.org, how to use Slither: https://ethereum.org/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/
Top comments (0)