DeFi Smart Contract Exploits: A Technical Knowledge Base (2020-2024)
A comprehensive technical analysis of major DeFi exploits, attack vectors, and mitigations for Clawditor's reference.
Overview
From 2020 to 2024, the DeFi ecosystem suffered $3.8B+ in losses across hundreds of exploits. This knowledge base documents the most significant attack vectors, their technical mechanics, and proven mitigations.
🔴 SC01: Reentrancy Attacks
Description
Reentrancy attacks exploit the ability to re-enter a vulnerable function before its execution is complete, allowing repeated state changes and fund drainage.
Technical Breakdown
The classic pattern involves:
- Attacker calls
withdraw()function - Contract transfers funds before updating state
- Attacker callback re-enters
withdraw()using the stale state - Repeat until funds are drained
// VULNERABLE CODE PATTERN
function withdraw() external {
uint balance = balances[msg.sender];
require(balance > 0);
// External call BEFORE state update
(bool success, ) = msg.sender.call{value: balance}("");
require(success);
// State update happens AFTER external call
balances[msg.sender] = 0;
}
Notable Exploits
Uniswap V1 (April 2020) - $1278 ETH
- Vector: Legacy reentrancy in Uniswap V1's
skim()function - Impact: 1278 ETH stolen from the lending protocol integrated with Uniswap
The DAO Hack (Historical Reference - 2016)
- Impact: 3.6M ETH stolen (~$50M at the time)
- Led to: Ethereum hard fork creating ETH and ETC
Mitigations
- Checks-Effects-Interactions Pattern: Update state before external calls
- Reentrancy Guards: Use
nonReentrantmodifiers (OpenZeppelin) - Mutex: Implement
sentinelvariables to prevent re-entry - Pull Payments: Use withdrawal patterns instead of push
// SECURE PATTERN
function withdraw() external {
uint balance = balances[msg.sender];
require(balance > 0);
// STATE UPDATE FIRST
balances[msg.sender] = 0;
// External call AFTER state update
(bool success, ) = msg.sender.call{value: balance}("");
require(success);
}
🔴 SC02: Price Oracle Manipulation
Description
Price oracle manipulation exploits vulnerabilities in how smart contracts fetch external data, allowing attackers to tamper with or control oracle feeds.
Technical Breakdown
Attackers exploit:
- Single-source oracle dependency
- Low-liquidity DEX pools
- Price manipulation within single transaction (flash loans)
// VULNERABLE: Single DEX price source
function getPrice(address token) internal view returns (uint256) {
(uint256 reserve0, uint256 reserve1,) =
IUniswapV2Pair(pair).getReserves();
return (reserve0 * PRICE_FEED_PRECISION) / reserve1;
}
Notable Exploits
bZx Flash Loan Attack (February 2020) - ~$350K
- Mechanism: Used flash loan to manipulate ETH/USD price on Kyber Network
- Steps:
- Borrow 10,000 ETH via flash loan
- Use funds to buy sUSD on Synthetix, driving price up
- Use inflated sUSD price as collateral on bZx
- Borrow more ETH than collateral value should allow
- Repay flash loan, keep profit
Cream Finance (Multiple incidents 2020-2021)
- Total Loss: $130M+ across multiple oracle manipulation attacks
- Vector: Repeated exploitation of AMP token pricing
Mitigations
- Time-Weighted Average Prices (TWAPs): Use price averages over time windows
- Multiple Oracle Sources: Aggregate prices from multiple DEXs
- Uniswap V3 TWAPs: Built-in time-weighted oracle with manipulation resistance
- Chainlink Price Feeds: Decentralized oracle network with external data aggregation
- Liquidity Thresholds: Only accept prices from pools with sufficient liquidity
🔴 SC03: Flash Loan Attacks
Description
Flash loans enable uncollateralized borrowing of massive sums within a single transaction. Attackers exploit this to manipulate markets or exploit protocol vulnerabilities.
Technical Breakdown
Flash loans work because:
- Loan must be repaid within the same transaction
- No upfront collateral required
- Attacker can orchestrate complex multi-step attacks
Notable Exploits
Euler Finance (March 2023) - $197M
The Vulnerability: Missing liquidity check in donateToReserves() function.
Attack Steps:
- Flash loan 30M DAI from Aave
- Deposit 20M DAI → Receive 19.5M eDAI (ETokens)
- Mint/borrrow 200M DTokens (95% LTV, self-collateralized)
- Repay 10M DAI (increases health score)
- Mint again (maximizes leverage)
- Donate 100M eDAI to reserves ← Critical exploit
- No health check on donation
- Position becomes undercollateralized
- Self-liquidate at maximum 20% discount
- Withdraw excess collateral from protocol
- Repay flash loan, net profit ~$197M
Code Vulnerability:
// donateToReserves() had NO health check
function donateToReserves(uint subAccountId, uint amount) external nonReentrant {
// ... balance updates ...
assetStorage.users[account].balance = encodeAmount(newBalance);
assetStorage.reserveBalance = assetCache.reserveBalance + amount;
// MISSING: health check or solvency verification
}
Platypus Finance (February 2023) - $8M
- Vector: Logic error in
emergencyWithdraw()- code order issue - Attacker withdrew more than deposited due to incorrect accounting
Mitigations
- Health Factor Checks: Verify solvency after all state-changing operations
- Invariant Testing: Test that health score never drops below 1
- Comprehensive Audits: Especially for post-deployment code changes
- Flash Loan Detection: Monitor for large flash loan activity
- Conservative Collateral Factors: Use lower LTV ratios
🔴 SC04: Access Control Vulnerabilities
Description
Access control flaws allow unauthorized users to access or modify contract data or functions.
2024 Impact
- $953.2M lost (largest category by value in 2024)
- 149 documented incidents
Common Vulnerabilities
- Missing Function Modifiers: Public/external functions without access checks
- Incorrectly Implemented Modifiers: Flawed
onlyOwnerlogic - Proxy Implementation Issues: Upgradeable contract vulnerabilities
Mitigations
- Principle of Least Privilege: Minimal permissions for each role
- Access Control Libraries: Use OpenZeppelin's
AccessControl,Ownable - Timelocks: Delay critical functions for security review
- Multi-Sig Requirements: Require multiple approvals for sensitive operations
🔴 SC05: Logic Errors / Business Logic Flaws
Description
Business logic vulnerabilities occur when contract behavior deviates from intended functionality.
Notable Exploits
PolyNetwork (August 2021) - $611M
- Vector: Cross-chain bridge logic flaw
- Mechanism: Attacker exploited
verifyHeader()function to falsify cross-chain messages - Outcome: Largest DeFi hack in history (funds partially returned)
xToken Finance (May 2021) - $25M
- Vector: Logic error in
xnftmigration contract - Impact: Users could mint infinite xnft tokens
Mitigations
- Formal Verification: Mathematically prove contract correctness
- Invariant Testing: Test that critical invariants always hold
- Formal Specification: Document expected behavior before coding
- Extensive Test Coverage: Unit, integration, and fuzz tests
🔴 SC06: Lack of Input Validation
Description
Insufficient input validation allows attackers to manipulate contracts with unexpected or harmful inputs.
2024 Impact
- $14.6M lost
- Primary cause of hacks in 2021, 2022, and 2024
Common Issues
- Unchecked Array Indices: Out-of-bounds access
- Integer Overflows/Underflows: (Pre-Solidity 0.8.0)
- Unexpected Token Types: Failing to validate token standards
Mitigations
- Input Sanitization: Validate all external inputs
- Safe Math: Use
SafeMath(pre-0.8) or built-in overflow checks (0.8+) - Reentrancy Guards: Apply to all externally-callable functions
- Gas Limit Awareness: Validate loop conditions
🔴 SC07: Unchecked External Calls
Description
Failing to verify external call success can lead to unintended consequences.
Technical Breakdown
// VULNERABLE
function callExternal(address target, bytes data) external {
target.call(data);
// No success check - contract continues even if call fails
}
// SECURE
function callExternal(address target, bytes data) external {
(bool success, bytes memory result) = target.call(data);
require(success, "External call failed");
}
Mitigations
- Always Check Return Values: Use
require(success)pattern - Low-Level Call Safety: Handle both success and return data
- Reentrancy Protection: Combine with reentrancy guards
🔴 SC08: Integer Overflow and Underflow
Description
Arithmetic operations exceeding fixed-size integer limits can cause unexpected wrapping behavior.
Historical Impact
- Common before Solidity 0.8.0
- Still relevant in custom implementations
Mitigations
- Use Solidity 0.8+: Built-in overflow protection
- OpenZeppelin SafeMath: For older codebases
- Explicit Bounds Checking: Before arithmetic operations
- Use Larger Integer Types: uint256 for maximum range
🔴 SC09: Insecure Randomness
Description
Blockchain's deterministic nature makes true randomness challenging, enabling exploitation of randomness-dependent functions.
Vulnerable Pattern
// VULNERABLE: Predictable randomness
function selectWinner() external {
uint256 random = uint256(keccak256(abi.encodePacked(
block.timestamp,
block.difficulty,
msg.sender
)));
// Attacker can predict and manipulate
}
Mitigations
- Chainlink VRF: Verifiable Random Function with cryptographic proofs
- Commit-Reveal Schemes: Two-phase randomness generation
- Block-Based Randomness Limitations: Accept limited unpredictability only
🔴 SC10: Denial of Service (DoS) Attacks
Description
DoS attacks exhaust contract resources to render it non-functional.
Common Vectors
- Gas Limit Vulnerabilities: Infinite loops or unbounded operations
- Unexpected Reverts: Attacker triggers revert in critical function
- Storage Bloat: Excessive storage writes
Mitigations
- Loop Bounds: Never iterate over unbounded arrays
- Pull over Push: Use withdrawal patterns instead of sending funds
- Gas Estimation: Calculate gas requirements before operations
- Circuit Breakers: Pause contracts during attacks
📊 Annual Loss Summary
| Year | Total Losses | Notable Incidents |
|---|---|---|
| 2020 | ~$140M | bZx, Uniswap V1 |
| 2021 | $3.7B | PolyNetwork ($611M), Cream Finance |
| 2022 | $3.8B (Peak) | Ronin Bridge ($624M), Wormhole ($326M) |
| 2023 | $1.7B | Euler Finance ($197M) |
| 2024 | $1.42B | Access Control dominates |
🎯 Key Takeaways for Auditing
-
Always Check State After External Calls
- Reentrancy is still the #1 killer
-
Oracle Independence
- Never rely on single-source price feeds
- TWAPs require meaningful time windows
-
Audit Code Changes Thoroughly
- Euler's
donateToReserves()was a post-fix that created a new vulnerability
- Euler's
-
Invariant Testing is Critical
- Health scores should never drop below thresholds
- Total borrows should never exceed deposits
-
Flash Loans Amplify Exploits
- Any oracle or liquidity vulnerability becomes critical with flash loans
📚 References
- OWASP Smart Contract Top 10 (2025)
- Euler Finance Post-Mortem
- Cyfrin Euler Analysis
- SolidityScan Web3HackHub
- Immunefi Crypto Losses Reports
Last Updated: January 2025 Clawditor Knowledge Base