By: Dikla Barda, Roman Zaikin, and Oded Vanunu
On November 30, 2025, Check Point Research detected a critical exploit targeting Yearn Finance’s yETH pool on Ethereum. Within hours, approximately $9 million was stolen from the protocol. The attacker achieved this by minting an astronomical number of tokens—235 septillion yETH (a 41-digit number)—while depositing only 16 wei, worth approximately $0.000000000000000045. This represents one of the most capital-efficient exploits in DeFi history.
The Vulnerability: Cached Storage Flaw
The attack exploited a critical flaw in how the protocol manages its internal accounting. The yETH pool caches calculated values in storage variables called packed_vbs[] to save on gas costs. These variables store virtual balance information that tells the protocol how much value exists in the pool. The vulnerability emerged when the pool was completely emptied—while the main supply counter correctly reset to zero, the cached packed_vbs[] values were never cleared.
How the Attack Was Executed
The attacker executed the exploit in three stages: First, they performed over ten deposit-and-withdrawal cycles using flash-loaned funds, deliberately leaving small residual values in the packed_vbs[] storage with each iteration. Second, they withdrew all remaining liquidity, bringing the supply to zero while the cached values remained populated with accumulated phantom balances. Finally, they deposited just 16 wei across eight tokens. The protocol detected that supply was zero and triggered its “first-ever deposit” logic, which read the cached values from storage. Instead of minting tokens based on the 16 wei actually deposited, the protocol read the accumulated phantom values and minted trillions upon trillions of LP tokens, giving the attacker control over the entire pool.


Background: The yETH Ecosystem
Protocol Architecture
Yearn Finance’s yETH is a liquid staking token representing a basket of Ethereum-based liquid staking derivatives (LSDs). The protocol consists of three main components:
- yETH Token – A standard ERC20 token with minter privileges
- yETH Pool – A weighted stableswap AMM (Automated Market Maker) pool
- Rate Providers – Oracle contracts that provide exchange rates for various LSDs
The pool contract implements a complex mathematical invariant based on weighted pool mechanics (similar to Balancer), adapted with Curve-style virtual balances for gas optimization.
The Pool’s Core Mechanism
Unlike simple constant-product AMMs (x × y = k), the yETH pool uses a sophisticated invariant that accounts for:
- Multiple assets (up to 32)
- Weighted ratios for each asset
- Exchange rates for LSDs (wstETH, rETH, cbETH, etc.)
- Virtual balances calculated as: vb_i = balance_i × rate_i / PRECISION
The pool stores these virtual balances in state variables to avoid recalculating them on every operation—a gas optimization that became the source of the vulnerability.
The Vulnerability: Incomplete State Cleanup
The Core Bug
The vulnerability exists in the interaction between two functions: remove_liquidity() and add_liquidity().
In remove_liquidity() (lines 590-654):

The Problem: When ALL LP tokens are burned (supply == 0), the virtual balances are decremented proportionally but never explicitly reset to zero. Due to rounding, tiny amounts remain in self.packed_vbs[].S
In add_liquidity() (lines 523-528):

In _calc_vb_prod_sum() (lines 729-744):

The Fatal Flaw: This function reads self.packed_vbs[asset] from storage, expecting them to be zero for a “first deposit” scenario. However, after multiple deposit/withdrawal cycles, these storage slots contain accumulated residual values that were never reset.
The Exploit Transaction: A Technical Walkthrough
Phase 1: Capital Acquisition
The attacker borrowed assets via flash loans from Balancer and Aave, obtaining wstETH, rETH, WETH, ETHx, and cbETH without upfront capital.
Phase 2: State Poisoning
The attacker executed multiple deposit-withdrawal cycles to accumulate residual values in packed_vbs[] storage. Each cycle deposited assets into vaults and the yETH pool, then withdrew portions. The virtual balances decremented but never fully reset.
Phase 3: Pool Drain
The attacker burned all remaining LP tokens, setting self.supply = 0 while self.packed_vbs[] retained accumulated values and was NOT reset.
Phase 4: Exploit
The attacker deposited minimal wei amounts across all supported tokens. The protocol treated this as an initial deposit and read stale storage values, minting septillions of yETH tokens instead of calculating from the actual dust deposit.

Phase 5: Fund Extraction
The attacker swapped the minted yETH tokens for WETH on Balancer pools and withdrew the underlying assets (sfrxETH, wstETH, ETHx, cbETH, rETH, apxETH, wOETH, mETH) from the pool.
Phase 6: Cleanup
The attacker converted all stolen assets to ETH via Uniswap V3 and other DEXs, repaid all flash loans with fees, and sent a portion to Tornado Cash for laundering while retaining the remainder as profit.
The Design Bug

1 wstETH ≈ 1.15 ETH
1 rETH ≈ 1.08 ETH
1 cbETH ≈ 1.00 ETH
To calculate how many LP tokens to give you, the pool needs to:
- Get the exchange rate for each token (expensive!)
- Calculate: virtual_balance = actual_balance × rate / PRECISION
- Sum all virtual balances
- Use this for the invariant calculation
Doing this EVERY time is expensive gas-wise, so instead of recalculating every time, the pool:
- Calculates once when you deposit/withdraw
- Stores the result in packed_vbs[]
- Reuses this cached value in future calculations
Expensive (done every operation without caching):

Cheap (with caching):

What Happens When It’s Not Zero When It Should Be?
Normal Flow (Working Correctly), scenario: Pool has 100 ETH worth of assets

Bug Scenario (When Not Reset) What the code ASSUMES when supply == 0:

What ACTUALLY happens after full withdrawal:

The pool was designed to store virtual balances in state to save gas on recalculations. This is a common optimization pattern in DeFi:

The Missing Edge Case
The developers correctly handled the normal flow:
- Adding liquidity updates virtual balances ✓
- Removing liquidity decrements virtual balances ✓
- Swapping updates virtual balances ✓
But they missed the edge case:
- Removing ALL liquidity should RESET virtual balances to zero ✗
The Implicit Assumption
The code assumed that when prev_supply == 0, this meant a “first-ever deposit” to a pristine pool. But after a full withdrawal, prev_supply == 0 while packed_vbs[] contained residual state from previous operations.

Conclusion
The yETH exploit stands as a masterclass in finding and exploiting subtle state management bugs. The attacker demonstrated deep understanding of:
- The protocol’s mathematical invariants
- Storage layout and state persistence
- How to manipulate state across multiple transactions
- How to maximize impact with minimal capital
For defenders, this exploit reinforces that correctness in complex systems requires explicit handling of ALL state transitions, not just the happy path. A missing state reset—a single oversight in 1000+ lines of code—enabled the theft of $9 million.
As DeFi protocols grow more complex, incorporating novel AMM designs and mathematical optimizations, the attack surface for such subtle bugs expands. The only defense is rigorous engineering discipline: explicit state management, comprehensive testing, and the humility to assume that if something CAN go wrong, eventually someone will find a way to exploit it.
How this could have been prevented
Onchain security must evolve from post-incident forensics to real-time prevention:
→ Simulate transactions before execution to catch abnormal token minting ratios (16 wei in → septillions out is not normal)
→ Track state across transaction sequences — this attack required 10+ deposit/withdrawal cycles to poison packed_vbs[]. Single-transaction monitoring would miss it
→ Block execution automatically when drain patterns emerge, not just alert after the fact
The difference:
- Seeing the exploit after $9M is gone vs.
- Stopping the malicious add_liquidity() before it executes
The Lesson: A single missing state reset — packed_vbs[] not clearing when supply hit zero — enabled this entire attack. Complex DeFi systems need runtime protection that understands protocol logic, not just signature-based detection.
Learn more about Check Point’s Blockchain Security solution here.


