Smart Contract Vulnerabilities
A comprehensive guide to the most common and dangerous smart contract vulnerabilities. Learn how they work and how to prevent them.
Reentrancy
CriticalAllows attackers to repeatedly call back into the vulnerable contract before the first execution completes.
Impact
Complete fund drainage
Famous Exploit
The DAO ($60M, 2016)
Frequency
35% of exploits
Integer Overflow/Underflow
HighArithmetic operations that exceed the maximum or minimum value wrap around, causing unexpected behavior.
Impact
Token theft, balance manipulation
Famous Exploit
BEC Token ($900M market cap, 2018)
Frequency
15% of exploits
Access Control
CriticalMissing or incorrect access modifiers allow unauthorized users to call privileged functions.
Impact
Contract takeover, fund theft
Famous Exploit
Parity Wallet ($280M, 2017)
Frequency
25% of exploits
Flash Loan Attacks
CriticalExploits that leverage uncollateralized loans to manipulate prices or governance in a single transaction.
Impact
Protocol manipulation, arbitrage
Famous Exploit
Euler Finance ($197M, 2023)
Frequency
12% of exploits
Oracle Manipulation
CriticalManipulating price feeds that smart contracts rely on for accurate external data.
Impact
Incorrect liquidations, fund theft
Famous Exploit
Cream Finance ($130M, 2021)
Frequency
18% of exploits
Front-Running / MEV
MediumMiners or bots observe pending transactions and insert their own to profit at users' expense.
Impact
Sandwich attacks, failed trades
Famous Exploit
Ongoing across all DEXs
Frequency
8% of exploits
Signature Replay
HighValid signatures can be reused across different contexts or chains when not properly validated.
Impact
Unauthorized transactions
Famous Exploit
Wormhole ($326M, 2022)
Frequency
5% of exploits
Unsafe Delegatecall
CriticalImproper use of delegatecall can allow attackers to execute arbitrary code in the context of the calling contract.
Impact
Complete contract takeover
Famous Exploit
Poly Network ($600M, 2021)
Frequency
4% of exploits
Deep Dive: Reentrancy
// VULNERABLE - DO NOT USE
function withdraw(uint256 amount) external {
require(balances[msg.sender] >= amount);
// External call BEFORE state update
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
// State updated AFTER external call
balances[msg.sender] -= amount; // TOO LATE!
}The attacker's fallback function can call withdraw() again before the balance is updated.
// SECURE - Checks-Effects-Interactions Pattern
function withdraw(uint256 amount) external nonReentrant {
// CHECKS
require(balances[msg.sender] >= amount, "Insufficient");
// EFFECTS - Update state BEFORE external call
balances[msg.sender] -= amount;
// INTERACTIONS - External call last
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}State is updated before the external call, and nonReentrant modifier prevents recursive calls.
How the Attack Works
Deposit
Attacker deposits funds into the contract
Withdraw
Attacker calls withdraw()
Callback
Attacker's fallback calls withdraw() again
Repeat
Loops until contract is drained
Prevention Strategies
- ✓Use the Checks-Effects-Interactions pattern
- ✓Implement OpenZeppelin's ReentrancyGuard
- ✓Use pull payments instead of push payments
- ✓Limit gas for external calls when possible
Scan Your Contract for Vulnerabilities
Use ChainLens to automatically detect these vulnerabilities and more in your smart contracts.
Try Free Vulnerability Scan