Skip to main content

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:

  1. Attacker calls withdraw() function
  2. Contract transfers funds before updating state
  3. Attacker callback re-enters withdraw() using the stale state
  4. 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

  1. Checks-Effects-Interactions Pattern: Update state before external calls
  2. Reentrancy Guards: Use nonReentrant modifiers (OpenZeppelin)
  3. Mutex: Implement sentinel variables to prevent re-entry
  4. 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:

  1. Single-source oracle dependency
  2. Low-liquidity DEX pools
  3. 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:
    1. Borrow 10,000 ETH via flash loan
    2. Use funds to buy sUSD on Synthetix, driving price up
    3. Use inflated sUSD price as collateral on bZx
    4. Borrow more ETH than collateral value should allow
    5. 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

  1. Time-Weighted Average Prices (TWAPs): Use price averages over time windows
  2. Multiple Oracle Sources: Aggregate prices from multiple DEXs
  3. Uniswap V3 TWAPs: Built-in time-weighted oracle with manipulation resistance
  4. Chainlink Price Feeds: Decentralized oracle network with external data aggregation
  5. 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:

  1. Flash loan 30M DAI from Aave
  2. Deposit 20M DAI → Receive 19.5M eDAI (ETokens)
  3. Mint/borrrow 200M DTokens (95% LTV, self-collateralized)
  4. Repay 10M DAI (increases health score)
  5. Mint again (maximizes leverage)
  6. Donate 100M eDAI to reserves ← Critical exploit
    • No health check on donation
    • Position becomes undercollateralized
  7. Self-liquidate at maximum 20% discount
  8. Withdraw excess collateral from protocol
  9. 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

  1. Health Factor Checks: Verify solvency after all state-changing operations
  2. Invariant Testing: Test that health score never drops below 1
  3. Comprehensive Audits: Especially for post-deployment code changes
  4. Flash Loan Detection: Monitor for large flash loan activity
  5. 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

  1. Missing Function Modifiers: Public/external functions without access checks
  2. Incorrectly Implemented Modifiers: Flawed onlyOwner logic
  3. Proxy Implementation Issues: Upgradeable contract vulnerabilities

Mitigations

  1. Principle of Least Privilege: Minimal permissions for each role
  2. Access Control Libraries: Use OpenZeppelin's AccessControl, Ownable
  3. Timelocks: Delay critical functions for security review
  4. 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 xnft migration contract
  • Impact: Users could mint infinite xnft tokens

Mitigations

  1. Formal Verification: Mathematically prove contract correctness
  2. Invariant Testing: Test that critical invariants always hold
  3. Formal Specification: Document expected behavior before coding
  4. 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

  1. Unchecked Array Indices: Out-of-bounds access
  2. Integer Overflows/Underflows: (Pre-Solidity 0.8.0)
  3. Unexpected Token Types: Failing to validate token standards

Mitigations

  1. Input Sanitization: Validate all external inputs
  2. Safe Math: Use SafeMath (pre-0.8) or built-in overflow checks (0.8+)
  3. Reentrancy Guards: Apply to all externally-callable functions
  4. 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

  1. Always Check Return Values: Use require(success) pattern
  2. Low-Level Call Safety: Handle both success and return data
  3. 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

  1. Use Solidity 0.8+: Built-in overflow protection
  2. OpenZeppelin SafeMath: For older codebases
  3. Explicit Bounds Checking: Before arithmetic operations
  4. 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

  1. Chainlink VRF: Verifiable Random Function with cryptographic proofs
  2. Commit-Reveal Schemes: Two-phase randomness generation
  3. 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

  1. Gas Limit Vulnerabilities: Infinite loops or unbounded operations
  2. Unexpected Reverts: Attacker triggers revert in critical function
  3. Storage Bloat: Excessive storage writes

Mitigations

  1. Loop Bounds: Never iterate over unbounded arrays
  2. Pull over Push: Use withdrawal patterns instead of sending funds
  3. Gas Estimation: Calculate gas requirements before operations
  4. Circuit Breakers: Pause contracts during attacks

📊 Annual Loss Summary

YearTotal LossesNotable Incidents
2020~$140MbZx, Uniswap V1
2021$3.7BPolyNetwork ($611M), Cream Finance
2022$3.8B (Peak)Ronin Bridge ($624M), Wormhole ($326M)
2023$1.7BEuler Finance ($197M)
2024$1.42BAccess Control dominates

🎯 Key Takeaways for Auditing

  1. Always Check State After External Calls

    • Reentrancy is still the #1 killer
  2. Oracle Independence

    • Never rely on single-source price feeds
    • TWAPs require meaningful time windows
  3. Audit Code Changes Thoroughly

    • Euler's donateToReserves() was a post-fix that created a new vulnerability
  4. Invariant Testing is Critical

    • Health scores should never drop below thresholds
    • Total borrows should never exceed deposits
  5. Flash Loans Amplify Exploits

    • Any oracle or liquidity vulnerability becomes critical with flash loans

📚 References


Last Updated: January 2025 Clawditor Knowledge Base