Lecture 17: Blockchain Security
Instructor: Yu Feng, UCSB
CS190: Blockchain Programming and Applications
Lecture 17 — This lecture note covers critical security paradigms in DeFi, focusing on the adversarial nature of the mempool, historical exploits like The DAO and Curve Finance, and the shift from low-level bugs to complex economic vulnerabilities.
Smart Contract Security: The Immutable Adversarial Environment
Unlike traditional software, bugs in Decentralized Finance (DeFi) can lead to immediate, permanent, and complete financial loss. The blockchain environment is relentlessly adversarial.
Irreversible Losses
DeFi bugs result in immediate, permanent financial loss with no undo.
"Dark Forest" Mempool
Automated bots constantly scan transactions for exploitable errors.
Historic Exploits
Lessons from The DAO (2016) and Curve Finance (2023) breaches.
The Stakes of DeFi Security
The crypto ecosystem has witnessed cumulative losses exceeding $59 billion over five years, with DeFi protocols bearing significant losses through smart contract failures.
H1 2025 data reveals sharp escalation: approximately $2.17 billion stolen—already surpassing all of 2024's losses. While incident frequency varies, value per incident has risen dramatically.
Protocol logic vulnerabilities remain the most critical category, with smart contract exploits reaching over $263 million in H1 2025—the worst period since early 2023.
The Blast Radius of Composability
Interconnected Protocols
DEXs, lending markets, and oracles are deeply linked, creating complex dependencies.
Single Point of Failure
A flaw in one protocol can rapidly spread its impact across the entire ecosystem.
Cascade Effect
Compromise of a base layer like Curve can destabilize dependent lending protocols.
Security transforms from a local problem (securing your code) into a systemic problem (securing your dependencies).
Vulnerability Taxonomy
Before examining specific exploits, we establish a taxonomy grouping vulnerabilities by root cause: arithmetic errors, ordering dependencies, resource exhaustion, and state management failures.
Arithmetic Vulnerabilities
Integer overflow and underflow in fixed-size EVM types
Transaction Ordering
Front-running and MEV exploitation via mempool visibility
Resource Exhaustion
DoS attacks via unbounded loops and gas limits
State Management
Reentrancy and inconsistent state during external calls
Arithmetic Vulnerabilities: Overflow and Underflow
In the EVM, numeric types are fixed-size integers (typically uint256). Unlike Python or Java, early Solidity allowed arithmetic wrapping without errors.
The Mechanism: If a uint8 variable holds 0, the operation x - 1 underflows to 255. Similarly, 255 + 1 overflows to 0—like points on a circular clock.
The Risk: Withdrawing 1 token more than owned could underflow balance to 2^{256} - 1, enabling complete protocol drainage.
Modern Mitigation: Solidity 0.8.0+ includes automatic checked arithmetic, reverting on overflow/underflow. Developers must remain vigilant with unchecked {...} blocks.
Transaction Ordering and MEV
Transactions don't execute instantaneously. They sit in a public mempool where observers can see user intent before execution. Block producers can reorder transactions based on gas tips, enabling profitable attacks.
1
Front-Run
Attacker buys Token X with higher gas, driving price up before victim's transaction
2
Victim Executes
User A's buy executes at inflated price, pushing it even higher
3
Back-Run
Attacker immediately sells, locking in risk-free profit at victim's expense
Defense: Set slippage tolerance to revert if price moves excessively. Use private transaction relays to hide from public mempool until on-chain inclusion.
Denial of Service Vulnerabilities
DoS in smart contracts typically freezes funds rather than crashing servers. Two primary patterns emerge:
Unbounded Iteration
Functions iterating over user arrays to distribute payments grow linearly in gas cost. Eventually, gas requirements exceed the block limit, making execution impossible and locking funds permanently.
Griefing Attacks
If a contract uses .transfer() to send ETH and the recipient reverts, a single malicious user can halt the entire system for all participants.
Solution: The "Pull over Push" pattern—contract updates balance mapping; users initiate their own withdrawals.
mapping(address => uint) public pendingWithdrawals; function withdraw() public { uint amount = pendingWithdrawals[msg.sender]; require(amount > 0); pendingWithdrawals[msg.sender] = 0; // Zero BEFORE sending payable(msg.sender).transfer(amount); }
The DAO Hack: Reentrancy in Practice
Reentrancy remains foundational to smart contract security. It's not merely a bug—it's a consequence of synchronous, atomic cross-contract calls in the EVM. The DAO exploitation in June 2016 led to Ethereum's hard fork and created Ethereum Classic.
The DAO: A Decentralized VC Fund
Launched April 2016, The DAO raised over 12 million ETH (~$150M), representing 14-15% of all ETH in circulation. It functioned as an investor-directed venture capital fund with a critical splitDAO exit mechanism.
The Exploit (June 17, 2016)
Attacker drained approximately 3.6 million ETH (~$60M) by exploiting the vulnerable withdrawal logic, calling splitDAO recursively before token balances were updated.
Understanding Reentrancy Mechanics
Reentrancy occurs when a malicious external contract calls back into a function before the original transaction completes its state updates, allowing repeated execution of the vulnerable logic.
Vulnerable Pattern
function withdraw() public { uint balance = userBalances[msg.sender]; require(balance > 0); // INTERACTION: Sending ETH msg.sender.call{value: balance}(""); // EFFECT: Balance update (TOO LATE!) userBalances[msg.sender] = 0; }
Attack Contract
fallback() external payable { if (address(vault).balance >= 1 ether) { vault.withdraw(); // Recursive } } function attack() external payable { vault.deposit{value: 1 ether}(); vault.withdraw(); // Starts the loop }
The state update (`userBalances[msg.sender] = 0`) happens after recursion, enabling the vault to see the original positive balance repeatedly.
The Checks-Effects-Interactions Pattern
The DAO codified the most important rule in smart contract development
01
Checks
Validate inputs and conditions using require statements to ensure prerequisites are met
02
Effects
Update all internal state variables first—zero balances, burn tokens, record changes
03
Interactions
Interact with external contracts or send ETH last, after state is consistent
function withdraw() public { uint balance = userBalances[msg.sender]; // 1. CHECKS require(balance > 0, "Insufficient balance"); // 2. EFFECTS (Update state FIRST) userBalances[msg.sender] = 0; // 3. INTERACTIONS (External call LAST) (bool success, ) = msg.sender.call{value: balance}(""); require(success, "Transfer failed"); }

Modern development mandates Reentrancy Guards (e.g., OpenZeppelin's nonReentrant modifier) using mutex flags to lock functions during execution.
Price Manipulation: The Modern Attack Vector
While reentrancy exploits execution flow, price manipulation attacks exploit economic dependencies between contracts. These have become dominant in modern DeFi, particularly with Flash Loans—uncollateralized loans borrowed and repaid within a single transaction.
Flash Loan
Attacker borrows massive capital (e.g., $100M) with no collateral
Price Manipulation
Dump liquidity into DEX, crashing or pumping spot price of target asset
Exploit
Interact with lending protocol that reads manipulated price as collateral value
Exit
Correct pool price, repay flash loan, pocket profit. Protocol left with bad debt
The vulnerability: protocols calculating collateral value by querying current "spot price" on a DEX like Uniswap or Curve.
Curve Finance and Read-Only Reentrancy
Curve Finance: Specialized AMM
A specialized AMM optimized for stablecoin swaps (USDC/DAI) and pegged assets (ETH/stETH).
Uses a complex invariant to create flatter pricing curves for lower slippage, making it highly efficient for similar assets.
Read-Only Reentrancy Vulnerability
A sophisticated 2023 vulnerability affecting protocols integrating with Curve, not Curve's pools themselves.
  • Classic Reentrancy: Attacker withdraws funds before a state update.
  • Read-Only Reentrancy: Attacker exploits an intermediate state to corrupt price oracles, tricking other protocols (like dForce, Sentiment, Midas) into bad decisions by trusting manipulated price data.
The get_virtual_price Manipulation
Protocols value Curve LP tokens using get_virtual_price(), calculating one LP token's value relative to pool assets:
\text{Virtual Price} = \frac{D}{\text{Total Supply of LP Tokens}}
where D represents total pool asset value.
Figure 7: During remove_liquidity, LP tokens burn immediately (reducing Total Supply), but internal balances update after ETH transfer. This creates an exploit window where:
\text{Virtual Price} = \frac{\text{Old (High) } D}{\text{New (Low) Total Supply}}
Result: Massive artificial price spike. Before: D = 100, Supply = 100, P = 1.0. During callback: D = 100, Supply = 50, P = 2.0. After: both return to 50, P = 1.0.
The dForce Attack Sequence
1
Flash Loan
Borrow ETH
2
Deposit
Add ETH to Curve pool, mint LP tokens
3
Trigger
Call remove_liquidity
4
Re-entry
Fallback triggered (ETH transfer)
5
Exploit
Call dForce with inflated LP price
6
Theft
Borrow stablecoins (worthless collateral)
7
Exit
Price normalizes, dForce debt
This exploit cost dForce approximately $3.6M and Sentiment $1M, leveraging temporary price inflation during the callback window.
The Vyper Compiler Bug (July 2023)
Distinct from read-only reentrancy, the Vyper bug was a catastrophic toolchain failure. Specific Vyper versions (0.2.15, 0.2.16, 0.3.0) contained a compiler bug where @nonreentrant guards failed.
Root Cause
The compiler assigned inconsistent storage slots to reentrancy locks across different functions. The @nonreentrant('lock') modifier appeared correct in source code but compiled to bytecode that never enforced mutual exclusion, enabling classic reentrancy attacks on Curve pools (CRV/ETH, aLETH/ETH) that drained over $69 million. This issue affected 3 Vyper versions.

Critical Lesson: Even perfect source code is insufficient. Supply chain security demands verifying compilers and build tools that translate code to bytecode.
Systemic Risks: Access Control
Access control exploits surged in 2025 statistics. Smart contracts contain privileged functions (mint(), pause(), upgrade()) protected by modifiers like onlyOwner.
Centralization Risk
If the private key controlling the Owner account is compromised via phishing, poor OpSec, or malware, attackers gain "god mode" over the protocol
Multi-Signature Wallets
Require M-of-N keys to execute privileged actions, distributing power and reducing single points of failure
Timelocks
Force 24-48 hour delays before privileged actions execute, giving users time to exit if they detect malicious behavior
The "Rug Pull": Malicious developers intentionally leave backdoors or use privileges to drain user funds.
Flash Loans as Force Multipliers
Democratizing Protocol Attacks
Flash loans, while financial primitives themselves, significantly amplify the impact of other vulnerabilities. They remove capital constraints, making exploits previously reserved for well-funded attackers accessible to anyone with a single transaction fee.
High Capital No Longer a Barrier
A price manipulation requiring over $100 million in capital can now be executed by anyone.
Single Transaction Fee
The only cost to perform a flash loan attack is the network's transaction fee.
Zero Collateral Required
Funds are borrowed and repaid within the same blockchain transaction, eliminating collateral needs.
This paradigm shift means any economic inefficiency exploitable with substantial capital will inevitably be targeted. The removal of capital barriers dramatically broadens the attack surface for decentralized protocols.
Signature Replay and EIP-712
Modern protocols use off-chain signatures for gasless transactions. A common vulnerability is signature replay, where signatures intended for specific actions are reused maliciously.
The Vulnerability
If signatures lack nonces (counters) or chainId, attackers can:
  • Replay signatures to execute withdrawals multiple times
  • Execute transactions on different blockchain forks
  • Reuse signatures across different contracts
EIP-712 Defense: Standardizes typed structured data signing. Always include nonce, chainId, and contract-specific domain separator in signed messages. This makes replay on different contracts or chains significantly harder.
Developer Security Checklist
Security is a process, not a feature. This checklist identifies "code smells" during design phase—scan when designing or reviewing contracts.
Logic & Flow
  • State updates before external calls?
  • nonReentrant on state-changing functions?
  • Pull vs. Push for fund distribution?
Data & Oracles
  • Using TWAP or Chainlink, not spot price?
  • Checking oracle data freshness?
  • Verifying read-only safety on integrations?
Access Control
  • Owner role necessary? Can it be renounced?
  • Critical changes delayed by Timelock?
  • Admin is Multisig, not single EOA?
Arithmetic & Types
  • Using Solidity 0.8.0+ for overflow protection?
  • Token decimals handled correctly?
  • Unit consistency across calculations?
The Path Forward
The DAO taught us execution order is paramount. Curve exploits taught us data validity is conditional on state consistency. The billions lost in 2024-2025 remind us the adversary constantly evolves.
The Challenge
Writing code that executes correctly in an adversarial, open, and immutable environment where mistakes are irreversible and instantly exploited
The Foundation
Distrust external calls, verify all data, and assume if your code can be broken, it will be broken
The Future
Formal verification proving code correctness mathematically and MEV mitigation strategies represent the frontier of blockchain security research