Reentrancy Attack Simulator
This simulates a classic vulnerable contract with a withdraw function.
This shows how to apply the Check-Effect-Interaction pattern to prevent reentrancy.
Click "Simulate Vulnerable Withdrawal" or "Simulate Secure Withdrawal" to see the outcome.
- Follow the Check-Effect-Interaction (C-E-I) pattern
- Use Reentrancy Guards like OpenZeppelin's nonReentrant
- Implement Pull-over-Push for payouts
- Use Static Analysis Tools like Slither
- Review fallback/receive functions carefully
Reentrancy attack is a vulnerability in smart contracts where an attacker can call a function repeatedly before the previous execution finishes, allowing the attacker to tamper with the contract's state and drain funds.
Quick Summary
- Reentrancy attacks let a malicious contract re‑enter a victim contract before state changes are saved.
- The classic example is the 2016 DAO hack, which lost ~3.6METH.
- Breaking the Check‑Effect‑Interaction (C‑E‑I) pattern is the root cause.
- Common defenses: reentrancy guards, mutexes, pull‑over‑push, and proper C‑E‑I implementation.
- Static analysis tools now flag potential reentrancy bugs during development.
How a Reentrancy Attack Works
Imagine a victim contract that lets users withdraw Ether:
- The attacker deposits a legitimate amount, establishing a balance.
- They call
withdraw()
. The contract checks the balance (Check phase). - Before the contract updates the attacker’s balance, it sends Ether to the attacker’s address (Interaction phase).
- The attacker’s contract has a malicious
fallback()
(orreceive()
) that immediately callswithdraw()
again. - Because the victim contract hasn’t yet reduced the attacker’s balance, the second call passes the balance check, and more Ether is sent.
- The loop repeats until the victim contract runs out of funds.
The flaw is obvious: the contract updates state **after** the external call, violating the C‑E‑I pattern.
The DAO Hack - A Real‑World Wake‑Up Call
In June2016, a decentralized autonomous organization (DAO) raised over 150MUSD worth of Ether. Its withdrawal function suffered from a classic reentrancy bug. An attacker created a contract, deposited 3.6METH, then repeatedly re‑entered the DAO’s splitDAO()
function. Within hours, the DAO lost roughly 3.6METH, prompting the controversial hard fork that created Ethereum (ETH) and Ethereum Classic (ETC).
The incident showed three things:
- Even well‑funded projects can overlook simple state‑sync issues.
- Reentrancy can wipe out billions of dollars when DeFi scales.
- Community governance can be forced to act dramatically (hard fork).
Key Concepts and Entities You Must Know
- Check‑Effect‑Interaction (C‑E‑I) pattern - a coding discipline that mandates checks, then state updates, then external calls.
- Fallback function - a special Solidity function (
fallback()
orreceive()
) that runs when a contract receives Ether without matching a function signature. - Reentrancy guard - a mutex‑style lock (often implemented via the
nonReentrant
modifier from OpenZeppelin). - Pull‑over‑push - a design where users claim funds instead of the contract pushing them.
- ERC‑777 and ERC‑1155 - token standards that include hook functions, which can be abused for reentrancy.

Prevention Techniques - From Basics to Advanced
Below is a quick‑reference table that compares the most common mitigation strategies.
Technique | How It Works | Pros | Cons |
---|---|---|---|
Check‑Effect‑Interaction | Perform state updates before any external call. | Simple, no extra gas cost. | Relies on developer discipline. |
Reentrancy Guard (mutex) | Set a boolean flag before external call; revert if flag is already true. | Easy to add via OpenZeppelin nonReentrant . |
Only one nonReentrant function can be called per transaction. |
Pull‑over‑Push | Store owed amounts and let users withdraw later. | Eliminates direct Ether pushes. | Requires additional bookkeeping. |
Using call with Checks |
Replace transfer /send with low‑level call , checking return values. |
Handles gas stipend changes safely. | Must still follow C‑E‑I; misuse can re‑introduce risk. |
Static Analysis Tools | Automated scans (e.g., Slither, MythX) flag potential reentrancy paths. | Finds hidden bugs before deployment. | False positives require manual review. |
Writing Secure Solidity - A Step‑by‑Step Checklist
- Identify every external call (Ether transfer, token
transfer
,call
,delegatecall
). - Apply the C‑E‑I pattern: Check conditions, Effect state changes, Interaction last.
- Add a reentrancy guard to any function that changes balances and performs external calls.
- Prefer the pull‑over‑push model for payouts.
- Use Solidity 0.8+ which has built‑in overflow checks (reduces other attack vectors).
- Run static analysis (Slither, MythX) and a formal verification step.
- Conduct a manual code review focusing on fallback/receive functions.
- Test with a malicious contract in a local fork (e.g., Hardhat or Foundry) to confirm the guard blocks re‑entry.
Detecting Reentrancy Vulnerabilities
Modern tools look for patterns such as:
- External calls placed before state updates.
- Absence of a
nonReentrant
modifier on functions that modify balances. - Fallback or
receive()
functions that invoke external contracts.
For instance, Slither’s reentrancy
detector flags functions where a call
occurs before a state variable write.
Beyond Reentrancy - Other Common Smart Contract Bugs
While reentrancy is notorious, developers also need to watch out for:
- Arithmetic overflows/underflows (mostly fixed in Solidity0.8).
- Access‑control mistakes (e.g., missing
onlyOwner
). - Uninitialized storage pointers.
- Denial‑of‑service via out‑of‑gas loops.
Understanding these helps you build a holistic security mindset.
Future Outlook - What’s Next for Reentrancy Defense?
The Ethereum roadmap includes EIPs that bake safety checks into the language (e.g., EIP‑2535 for modular contracts). Auditing firms are also integrating machine‑learning models that predict reentrancy pathways before code is even written. As DeFi TVL tops $40B, the incentive to find a new reentrancy vector stays high, so continuous education and tool upgrades are a must.

Frequently Asked Questions
What exactly is a reentrancy attack?
It is a technique where an attacker repeatedly calls a vulnerable contract's function before the previous call finishes, allowing the attacker to manipulate the contract's state and extract funds.
Why did the DAO hack succeed?
The DAO’s withdrawal function sent Ether before updating the attacker’s balance, breaking the C‑E‑I pattern. The attacker’s fallback function re‑entered the withdrawal repeatedly, draining ~3.6METH.
How does a reentrancy guard work?
A guard sets a boolean flag (e.g., _locked
) at the start of a protected function. If the flag is already true, the call reverts, preventing nested entry. OpenZeppelin’s nonReentrant
modifier implements this pattern.
Is the pull‑over‑push pattern enough on its own?
Pull‑over‑push greatly reduces risk because the contract never initiates an external Ether transfer. However, you should still follow C‑E‑I and consider a reentrancy guard for added safety.
Can static analysis miss reentrancy bugs?
Yes. Tools may generate false negatives when the contract uses complex control flow or indirect calls. Manual review and testing with a malicious contract remain essential.
Shamalama Dee
January 4 2025The Check‑Effect‑Interaction pattern is the first line of defense against reentrancy. You start by checking the caller’s balance, then you update the state, and finally you interact with external contracts. This ordering guarantees that an attacker can’t exploit the contract before their balance is reduced. It’s simple, but many developers still get it wrong.
scott bell
January 5 2025Reentrancy attacks are like a sneaky ninja that jumps in before you even finish your move, stealing the loot while you’re still mid‑step. It’s wild how a single misplaced call can drain an entire vault!
vincent gaytano
January 5 2025Sure, the DAO hack was just a little glitch in the matrix, nothing the big blockchain powers can’t fix, right? Meanwhile, the same old story repeats with every new DeFi launch, and we’re all supposed to trust the next “secure” contract.
Dyeshanae Navarro
January 6 2025Pull‑over‑push stops the bad guys.
Matt Potter
January 7 2025Don’t let a single vulnerable function ruin your project-lock it down with a nonReentrant guard and you’ll be laughing at attackers.
Marli Ramos
January 7 2025lol this stuff is sooo easy 😅 just use OpenZeppelin and chill.
Christina Lombardi-Somaschini
January 8 2025When dealing with smart contract security, it is essential to adopt a multi‑layered approach; relying on a single mitigation technique is insufficient. The Check‑Effect‑Interaction (C‑E‑I) pattern, for instance, should be implemented as a baseline defense, ensuring that state changes precede any external calls.
Beyond C‑E‑I, incorporating a reentrancy guard, such as OpenZeppelin's
nonReentrant
modifier, adds a mutex that blocks nested entries.Nevertheless, developers must remain vigilant about fallback and receive functions, as they can be inadvertently leveraged for re‑entry attacks.
Static analysis tools like Slither or MythX provide automated detection of unsafe call patterns, flagging potential reentrancy vectors before deployment.
Formal verification, though more demanding, offers mathematical proof that a contract adheres to its intended invariants, thereby eliminating whole classes of bugs.
Another practical safeguard is the pull‑over‑push model, which eliminates the need for the contract to send Ether directly, instead allowing users to withdraw owed funds at their convenience.
When using the pull‑over‑push pattern, it remains crucial to still follow C‑E‑I for any internal state updates that occur during the withdrawal process.
In addition, developers should enforce strict access control on functions that modify critical balances, employing modifiers such as
onlyOwner
or role‑based permissions.Gas considerations also play a role; low‑level
call
should be used with caution, checking its return value to avoid silent failures.Testing with malicious contracts on local forks (Hardhat, Foundry) replicates real‑world attack scenarios, confirming that guards function as expected.
Moreover, continuous integration pipelines should integrate security checks to catch regressions early.
Community audits and peer reviews further increase confidence, as multiple eyes can spot subtle flaws missed by automated tools.
Finally, staying updated with emerging EIPs that introduce language‑level safety checks ensures long‑term resilience against evolving attack techniques.
katie sears
January 9 2025It is noteworthy that the adoption of the C‑E‑I paradigm, coupled with a robust reentrancy guard, forms an effective bulwark against exploit attempts. Moreover, encouraging developers to employ pull‑over‑push mechanisms further diminishes attack surface.
Gaurav Joshi
January 10 2025One must recognize that when a contract neglects the proper ordering of checks, effects, and interactions, it paves the way for malicious re‑entries. Ethical coding standards dictate that developers avoid such pitfalls.
Kathryn Moore
January 10 2025Use a reentrancy guard and pull‑over‑push-simple and effective.
Christine Wray
January 11 2025Balancing readability with security is key; clear comments help reviewers spot missing guards quickly.
roshan nair
January 12 2025Hey folks, don’t forget to test your contracts with a malicious attacker contract on a local fork-this real‑world simulation can catch reentrancy bugs that static scanners might miss. Also, sprinkle in colorful error messages so it’s obvious when something goes wrong!
Jay K
January 12 2025In accordance with best practices, one should meticulously audit fallback functions and ensure that they do not invoke external calls without prior state updates.
Kimberly M
January 13 2025Great points above! 😊 Remember, the community thrives when we share safeguards and encourage each other to write secure code.
Navneet kaur
January 14 2025Check the fallback, then update state, then call. Simple.
Marketta Hawkins
January 14 2025Our nation’s developers must lead the world in secure smart contracts; we can’t let foreign actors exploit our code.
Drizzy Drake
January 15 2025It’s truly inspiring to see how the community evolves with each new security tool. When you combine thorough testing, formal verification, and peer reviews, you build contracts that stand the test of time. So keep sharing knowledge, stay curious, and never underestimate the power of a well‑placed guard.
AJAY KUMAR
January 16 2025We must protect our blockchain from the hordes of attackers, and only the strongest, most disciplined code will survive!
bob newman
January 16 2025Honestly, if you’re still writing contracts without a nonReentrant modifier, you’re practically handing money to scammers.
Anil Paudyal
January 17 2025Test, guard, repeat.