Skip to content

Revision · Security

The Security part took the book’s one question — how do untrusting strangers agree on the state of a shared world computer? — and turned it adversarial. Every earlier part assumed the participants merely mistrusted each other’s honesty. Here we assumed they mistrust each other’s intent: some caller, right now, is running your code not to use it but to break it, because breaking it pays. This page recaps the whole part in one breath — the single root cause under every contract-level bug, the dated heist that taught each lesson, and the way MEV slides the attack surface out of your Solidity and into the order of transactions in a block.

The thing to walk away with is not a list of five bugs. It is one thesis, stated five ways, plus one twist. Hold the thesis and each incident becomes an instance of it rather than a fact to memorise.

On an immutable, composable, adversarial state machine, every trust assumption baked into a contract’s code is an attack surface, and every successful exploit is a direct, irreversible theft — because there is no gap between “vulnerability” and “loss.” On a private server a bug is an embarrassment you patch on Tuesday. On a public contract holding other people’s money, the bug is an open safe with the combination printed on the door, and the exploit is the disclosure.

Three properties, each a gift in the Smart Contracts part, became this part’s threat model:

property the gift the threat
────────────────────────────────────────────────────────────────────────────────
immutable nobody can quietly change the rules you cannot patch a live bug
composable anyone can build on your contract anyone can call you mid-call
adversarial econ. a public market, no gatekeeper a profitable exploit WILL be found

Everything below is that table happening to real money on a real date.

The contract-level family: four bugs, one betrayal

Section titled “The contract-level family: four bugs, one betrayal”

The first four incidents are all the same mistake wearing different clothes: your code trusted an external actor to behave, and the actor was under no obligation to. Reentrancy trusts the recipient of a transfer. Overflow trusts arithmetic to stay in range. Access control trusts callers to be who they should be. Oracle manipulation trusts an on-chain price to reflect reality. Each betrayal has a date attached, because in this part the rule is the scar left by a loss.

Covered in Reentrancy and The DAO. The DAO’s withdraw path sent ETH to the caller before zeroing the caller’s internal balance. Sending ETH hands control to the recipient’s fallback, which called withdraw again while the balance check still passed — a loop that drained roughly 3.6M ETH. The lesson was an ordering discipline, Checks-Effects-Interactions: do all your checks, commit all your state effects, and only then touch the outside world. The fallout was a chain-splitting hard fork that produced Ethereum (ETH) and Ethereum Classic (ETC) — the network’s clearest admission that on an immutable machine, the only “undo” is to fork reality itself.

what The DAO WROTE (looks fine) what the ATTACKER ran
───────────────────────────── ───────────────────────────────
withdraw(): fallback(): ← runs during send()
1. check caller has 1 ETH └─ call withdraw() again!
2. send 1 ETH to caller ───────────► (step 1 still passes:
3. effect set balance = 0 balance not zeroed yet)

Covered in Integer Overflow Before Solidity 0.8. Pre-0.8 Solidity let arithmetic wrap silently: on a uint256, 0 - 1 becomes a number near 2²⁵⁶. In April 2018 the “batchOverflow” class of ERC-20 bugs multiplied a token amount by a recipient count until the product overflowed, letting an attacker mint astronomical balances out of nothing and forcing exchanges to halt affected token deposits. The fix arrived in two stages: the SafeMath library, then checked arithmetic by default in Solidity ≥ 0.8, which reverts on overflow instead of wrapping. The betrayal here was trusting the machine’s number type to behave like a mathematician’s integer.

Access control — the Parity multisig, 2017

Section titled “Access control — the Parity multisig, 2017”

Covered in Access Control and the Parity Multisig. The Parity multisig wallet delegated its logic to a shared library. In November 2017 an unguarded initWallet on that library let an outsider become its owner and then call selfdestruct, deleting the library that hundreds of wallets depended on and freezing roughly 513K ETH — funds that were never stolen but can never move again. The lesson: guard every state-changing entry point, initialise exactly once, and treat shared library code as part of your own trust boundary. The betrayal was trusting that a function which “should” only be callable by the owner was actually restricted to the owner.

Oracle manipulation — flash-loan price attacks, 2020–

Section titled “Oracle manipulation — flash-loan price attacks, 2020–”

Covered in Oracle Manipulation and Flash Loans. A flash loan lets an attacker borrow an enormous sum with no collateral, as long as it is repaid in the same transaction. Starting in 2020, attackers used flash-loaned capital to shove a DEX’s spot price far off-market for a single block, then borrowed or liquidated against a lending protocol that naively read that spot price as truth — repaying the loan and pocketing the difference atomically. The lesson: never trust a single-block spot price; use manipulation-resistant sources such as time-weighted average prices (TWAPs) or aggregated feeds. The betrayal was trusting a number read on-chain to reflect the world, when the attacker controlled the world for the length of one transaction.

The recurring defense: never trust an external actor mid-computation

Section titled “The recurring defense: never trust an external actor mid-computation”

Line the four defenses up and they collapse into one principle. Each is an instance of do not extend trust to an external actor in the middle of a computation whose invariants you have not yet re-established.

bug the trusted external actor the defense (one principle, four faces)
────────────────────────────────────────────────────────────────────────────────────────
reentrancy the call recipient Checks-Effects-Interactions: finish
your effects BEFORE you call out
integer overflow the arithmetic operation checked arithmetic: revert on wrap,
never trust a value to stay in range
access control the caller's identity explicit authorization: prove who is
calling before mutating state
oracle manipulation an on-chain price feed manipulation-resistant oracles: never
trust a single-block, movable number

Reentrancy is the purest form — you literally called out to the attacker before your bookkeeping was consistent. The other three are the same shape one level up: you trusted a value, an identity, or a price that an adversary could bend for exactly as long as they needed to. The discipline is to treat every external touch — a transfer, an arithmetic result, an incoming call, a price read — as hostile until your own invariants are re-established.

The twist: MEV moves the attack surface from code to ordering

Section titled “The twist: MEV moves the attack surface from code to ordering”

The fifth page, MEV: Front-running, Sandwiching & PBS, is where the shape of the whole part changes. Here no contract is buggy. The victim’s code did exactly what it should. The loss comes from the state machine’s own rules: pending transactions are public before they are final, and whoever assembles them into a block chooses their order. Ordering power is value. Maximal Extractable Value (MEV) is the profit a block builder captures by inserting, reordering, or sandwiching other people’s transactions — buying just before a big pending swap and selling just after, for instance.

contract-level (pages 2–5) protocol-level / MEV (page 6)
───────────────────────────── ──────────────────────────────────
the code is WRONG the code is FINE
attacker calls it "legally" attacker reorders/inserts txs
fix = write correct Solidity fix = change how blocks are built

The crucial point for revision: Flashbots and Proposer-Builder Separation (PBS) do not eliminate MEV — they restructure it. MEV is a consequence of having an ordered ledger built by a party who can see pending transactions; you cannot make that value zero without giving up either the public mempool or the freedom to order. What PBS does is separate the roles — a specialised builder assembles the most valuable block and the validator (proposer) merely picks the winning bid — so the extraction happens in an open auction rather than as a chaotic public gas war that congests the whole chain. Contract authors still defend at their own layer with slippage limits and, increasingly, private orderflow, but the attack surface itself has moved out of the code and into the pipeline that decides which transaction lands first.

The book’s second question is what does it cost to run a shared world computer? Earlier parts answered in gas, storage, and consensus overhead. This part adds the sharpest cost of all: the perpetual, adversarial cost of keeping the state transitions honest.

Consensus makes untrusting strangers agree on which transition happened. Security is what happens when a stranger crafts a transition that is perfectly valid by the rules and yet ruinous by intent — and the network will faithfully, unanimously, irreversibly agree on your loss. The more perfectly the world computer agrees, the more perfectly it agrees to the exploit too. There is no referee to appeal to.

So the true cost of the world computer is not only the gas to execute a call. It is the standing bounty every deployed line places on its own correctness, the audits and formal proofs and reentrancy guards that bounty demands, and — at the protocol layer — the ongoing engineering (Flashbots, PBS, private orderflow) required to keep ordering power from quietly taxing every ordinary user. A shared world computer that untrusting strangers can rely on is not a thing you build once. It is a thing you defend forever, because the same openness that lets strangers trust it is the openness that pays adversaries to break it.

To re-run any single lesson from its root cause, return to the part’s Overview and follow the roadmap: The DAOoverflowParityoraclesMEV.