Skip to main content

Reentrancy Attack Simulator

Watch step-by-step how an attacker drains a vault through recursive re-entry.

Simulation Mode
Deposit:
Speed:
1
SETUP
Attacker deposits 1 ETH
2
ATTACK
Attacker calls withdraw()
3
CHECK
require(deposits[attacker] >= amount) ✔ (1 >= 1)
4
SENDDANGER
Vault sends 1 ETH to Attacker (triggers receive())
5
REENTERDANGERdepth: 1
receive() re-enters withdraw() (depth: 1)
6
CHECKdepth: 1
require(deposits[attacker] >= amount) ✔ (1 >= 1)
7
SENDDANGERdepth: 1
Vault sends 1 ETH to Attacker (triggers receive())
8
REENTERDANGERdepth: 2
receive() re-enters withdraw() (depth: 2)
9
CHECKdepth: 2
require(deposits[attacker] >= amount) ✔ (1 >= 1)
10
SENDDANGERdepth: 2
Vault sends 1 ETH to Attacker (triggers receive())
11
REENTERDANGERdepth: 3
receive() re-enters withdraw() (depth: 3)
12
CHECKdepth: 3
require(deposits[attacker] >= amount) ✔ (1 >= 1)
13
SENDDANGERdepth: 3
Vault sends 1 ETH to Attacker (triggers receive())
14
REENTERDANGERdepth: 4
receive() re-enters withdraw() (depth: 4)
15
CHECKdepth: 4
require(deposits[attacker] >= amount) ✔ (1 >= 1)
16
SENDDANGERdepth: 4
Vault sends 1 ETH to Attacker (triggers receive())
17
REENTERDANGERdepth: 5
receive() re-enters withdraw() (depth: 5)
18
CHECKdepth: 5
require(deposits[attacker] >= amount) ✔ (1 >= 1)
19
SENDDANGERdepth: 5
Vault sends 1 ETH to Attacker (triggers receive())
20
UPDATE
deposits[attacker] = 0 (state updated AFTER all sends!)
21
RESULT
Attack partially succeeded. Attacker withdrew 6 ETH.
10 ETH
Vault Balance
Users: 10 ETH deposited
0 ETH
Attacker Wallet
0xAttacker
0 ETH
Attacker Deposit
deposits[attacker]
Call Stack Visualization

Press Start to begin the simulation

What is Reentrancy?

An external call re-enters the calling function before state updates complete, allowing recursive fund extraction.

Why is it Dangerous?

The attacker's receive() callback calls withdraw() again while the vault still thinks they have a balance. Over $250M stolen.

The CEI Pattern

Checks-Effects-Interactions: validate inputs, update state, THEN make external calls. The simplest and most gas-efficient fix.

Did You Know?

.call{value: amount}('') forwards all gas — flexible but requires reentrancy protection.

Previous: Require/Revert/Assert
Back to error handling comparison