Track 7 · The Breach Lab · lesson 2

Now make it hold

15 min


You drained that vault. Now make it hold.

The exploit you wrote last lesson is aimed at the vault below. Fix the vault, run the exploit against it, and keep going until the attack fails.

VulnerableVault.solPatch
Loading editor…
Fix the vault so your own exploit fails.

VulnerableVault

? ETH

Nudge
The exploit relies on your balance still being set when it re-enters. What if it weren't?
Show me the approach
Checks-effects-interactions: do the state change (the effect) before the external call (the interaction).
Show me the code
Move `balances[msg.sender] = 0;` to above the `call`.
Explain the exploit
Now when the attacker re-enters, `bal` reads zero and `require(bal > 0)` reverts the reentrant call. A reentrancy guard modifier is the other common fix, but correct ordering costs no extra gas and is preferable when you can manage it.

The pattern that would have saved The DAO

Checks. Effects. Interactions. In that order, every time.

  1. Checks — validate everything. Caller, balance, inputs.
  2. Effects — update your own state.
  3. Interactions — only now call anything external.

The vault broke the order: it interacted (sent ETH) before applying the effect (zeroing the balance). Reversing those two lines closes the window entirely.

When the attacker re-enters, bal reads zero and require(bal > 0) reverts the reentrant call. There is nothing to steal, because the books were already updated before control ever left the contract.

The other fix

Ordering is the better fix when you can manage it — it costs no extra gas. But sometimes the logic genuinely cannot be reordered, and then you reach for a reentrancy guard:

modifier nonReentrant() {
    require(!locked, "reentrant");
    locked = true;
    _;
    locked = false;
}

This is the wrapping modifier from track 4, and it is exactly what OpenZeppelin's ReentrancyGuard provides. It sets a flag on the way in and refuses any call that arrives while the flag is set.

Predict

You add a reentrancy guard but STILL send ETH before updating the balance. Are you safe?

Choose one answer

Check

Why is reordering preferred over a guard when both would work?

Choose one answer

Worth remembering

  • Checks-effects-interactions: validate, update your state, then call out — in that order.
  • Reversing the effect and interaction closes the reentrancy window entirely.
  • A reentrancy guard is the fallback when ordering cannot be fixed.
  • Prefer reordering: it costs no gas and leaves no window.
  • Read-only reentrancy can still bite a guarded contract with wrong ordering.