The $9M yETH Exploit: How 16 Wei Became Infinite Tokens
嗯,用户让我帮忙总结一下这篇文章的内容,控制在一百个字以内。首先,我需要通读整篇文章,理解主要事件和关键点。 文章讲的是Yearn Finance的yETH池在2025年11月30日被攻击,损失了约900万美元。攻击者利用了一个缓存存储漏洞,通过存入极小金额的 wei,却成功mint了大量yETH tokens。这个漏洞是因为当池子被完全清空时,缓存的虚拟余额没有被重置,导致协议错误地读取了旧值。 接下来,我需要提取关键信息:攻击时间、损失金额、漏洞类型、攻击手法以及影响。然后用简洁的语言把这些点整合起来,确保不超过100字。 可能会遇到的问题是如何在有限的字数内涵盖所有重要信息。因此,需要精简表达,突出主要事件和原因。 最后,检查总结是否准确反映了文章内容,并且符合用户的要求。 </think> Yearn Finance的yETH池因缓存存储漏洞遭攻击,损失约900万美元。攻击者利用池子清空后虚拟余额未重置的缺陷,在存入极小金额后 mint 了大量 tokens。此漏洞暴露了复杂 DeFi 系统中状态管理的风险。 2025-12-2 13:41:31 Author: research.checkpoint.com(查看原文) 阅读量:5 收藏

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:

  1. yETH Token – A standard ERC20 token with minter privileges
  2. yETH Pool – A weighted stableswap AMM (Automated Market Maker) pool
  3. 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

The yETH pool holds multiple LSDs (liquid staking derivatives) with
different values for example:
The yETH pool holds multiple LSDs (liquid staking derivatives) with different values for example:

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:

  1. Get the exchange rate for each token (expensive!)
  2. Calculate: virtual_balance = actual_balance × rate / PRECISION
  3. Sum all virtual balances
  4. 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.


文章来源: https://research.checkpoint.com/2025/16-wei/
如有侵权请联系:admin#unsafe.sh