Why I read exploits backwards
Start at the drained wallet, not the bug. Reading an exploit chain in reverse is the fastest way to understand what actually went wrong.
Most write-ups start at the bug. Mine usually start at the balance that isn't there anymore.
The drained wallet is the only thing in the whole story that is definitely true. Everything else — the contract, the docs, the audit, the tweetstorm — is someone's account of events. So I begin with the fact and work back towards the cause.
The shape of the loop
An exploit chain is a sequence of small permissions that shouldn't have been available at the same time. Reading it backwards turns a mystery into a checklist:
- What changed? Balances, storage slots, approvals. Start with the delta.
- What was allowed to change it? Every state transition has a caller. Who was the caller?
- Why did that caller have the right? This is where the bug normally lives — usually a single
requirethat was never written. - What else could have done it? If the answer is "nothing", the chain is complete.
Working forwards, you get lost in implementation detail. Working backwards, every step has to justify itself by an effect you already know happened.
A small example
The pattern below shows up constantly. Nothing exotic — an assumption that a value comes from somewhere trustworthy, when it actually comes from the caller:
function claim(uint256 amount) external {
// Looks fine. Isn't.
require(amount <= balances[msg.sender], "insufficient");
balances[msg.sender] -= amount;
token.transfer(msg.sender, amount);
}
If balances can be written by anything other than a deposit path, the require is decoration.
Found forwards, this reads as correct. Found backwards from a transfer that shouldn't have existed,
it reads as a missing question: who was allowed to set that number?
What I actually write down
I keep a single page per chain: the effect at the top, the cause at the bottom, and every hop between them with one line of evidence. If a hop can't be evidenced, it's a guess, and guesses go in a different column until they're confirmed.
The satisfying part of security research isn't the clever bug. It's the moment a vague hunch becomes a line in a file that someone can fix.
That's the whole method. It isn't glamorous, and it works on everything from a smart contract to a network appliance to an internal dashboard nobody has looked at since 2019.