Calculated from recorded token losses using historical USD prices at the incident time.
0x35f8d2f572fceaac9288e5d462117850ef2694786992a8c3f6d02612277b08770xf0358e8c3cd5fa238a29301d0bea3d63a17bedbeEthereum0xd55ada00494d96ce1029c201425249f9dfd216ccEthereumOn Ethereum mainnet block 11129474, transaction 0x35f8d2f572fceaac9288e5d462117850ef2694786992a8c3f6d02612277b0877 used public Uniswap flash liquidity plus public Curve and Harvest entrypoints to extract 962,108.989874 USDC from Harvest's FARM_USDC vault at 0xf0358e8c3cd5fa238a29301d0bea3d63a17bedbe. The attacker borrowed 18,308,555.417594 USDT and 50,000,000 USDC, distorted the Curve y pool spot withdrawal quote, deposited into the vault while Harvest undervalued its strategy assets, reversed the distortion, and then withdrew more USDC than had been deposited. The sender EOA 0xf224ab004461540778a914ea397c589b677e27bb finished the transaction with 14.805066725 ETH more than it started with after paying 5.194933275 ETH in block fees, while the exploit contract retained 691,781.898529 USDC.
The root cause is that Harvest priced FARM_USDC shares from a manipulable Curve y-pool single-coin withdrawal quote instead of from a manipulation-resistant valuation source. VaultV1 minted and burned shares against underlyingBalanceWithInvestment(), and CRVStrategyStableMainnet computed that balance through investedUnderlyingBalance() and , which delegated to a Curve convertor path backed by . Because large same-transaction Curve trades move that quote immediately, the attacker could over-mint shares during the depressed state and over-redeem after reversing the distortion.
underlyingValueFromYCrv()calc_withdraw_one_coinFARM_USDC is a Harvest vault that accepts USDC, issues vault shares, and delegates most capital to CRVStrategyStableMainnet at 0xd55ada00494d96ce1029c201425249f9dfd216cc. The vault share price is not derived from a fixed accounting unit inside the vault alone. Instead, it depends on the strategy-reported invested underlying value, so any weakness in the strategy valuation path directly affects share mint and burn outcomes.
The critical external dependency is the Curve y pool at 0x45f783cce6b7ff23b2ab2d70e416cdb7d6055f51. Its calc_withdraw_one_coin path is a slippage-sensitive spot quote, not a robust oracle. Large pool imbalances can move that quote within the same transaction. Harvest nevertheless used that path to value the strategy's yCRV-backed position, while depositArbCheck() tolerated movements within an arb-tolerance band around the stored checkpoint. That left a range in which an attacker could manipulate Curve spot pricing enough to distort Harvest share accounting while still remaining within the strategy's acceptance bounds.
This incident is an ATTACK-category ACT exploit against Harvest's share-accounting design. The key invariant is that a vault share should represent a stable pro-rata claim on real underlying value, and transient spot slippage in an external AMM must never let one user mint shares below fair value and redeem them above fair value in the same transaction. Harvest broke that invariant because the vault's mint and burn denominator depended on a Curve quote that an unprivileged attacker could move on demand.
The code-level breakpoint sits on the path from VaultV1._deposit() and VaultV1._withdraw() to underlyingBalanceWithInvestment(), then to CRVStrategyStableMainnet.investedUnderlyingBalance(), and then to underlyingValueFromYCrv(). The strategy's convertor delegated to Curve's single-coin withdrawal quote, so a manipulated Curve pool state changed the balance figure Harvest used for share issuance and redemption. The attacker first pushed Curve into a state where Harvest read the strategy's USDC value too low, then deposited USDC and received too many vault shares. After reversing the pool imbalance, the same shares redeemed against a higher denominator and returned more USDC than had been deposited. Three repetitions of that sequence produced the full vault loss.
The on-chain evidence supports the exploit as a complete, single-transaction accounting attack. Seed metadata identifies the sender EOA 0xf224ab004461540778a914ea397c589b677e27bb, the exploit contract 0xc6028a9fa486f52efd2b95b949ac630d287ce0af, and the target block 11129474. The sender called the exploit contract directly, and the trace shows two nested Uniswap V2 flash swaps that sourced the capital required to manipulate Curve and interact with Harvest.
The relevant Harvest accounting path is summarized in the auditor artifacts and root-cause record as follows:
VaultV1._deposit/_withdraw
-> underlyingBalanceWithInvestment()
-> CRVStrategyStableMainnet.investedUnderlyingBalance()
-> underlyingValueFromYCrv()
-> Curve convertor / calc_withdraw_one_coin
That path is the defect boundary. Harvest used it both when minting shares and when redeeming them, so any same-transaction distortion of the Curve quote directly changed the number of shares a deposit bought and the amount of USDC a withdrawal returned. The root-cause artifact states the mint formula as amount * totalSupply / underlyingBalanceWithInvestment() and the burn path as underlyingBalanceWithInvestment() * shares / totalSupply, which is exactly the accounting shape that becomes exploitable when the denominator can be pushed down and then back up around the same share position.
The seed balance diff confirms the measurable result of that defect. The FARM_USDC vault's USDC balance fell from 72,825,240,824,416 to 71,863,131,834,542, a delta of -962,108,989,874 raw USDC units. The exploit contract ended with 691,781,898,529 raw USDC units, and the sender EOA gained 14.805066725 ETH net after fees. Those deltas match the exploit narrative and establish both victim loss and attacker benefit.
The adversary strategy was a single-transaction flash-loan attack with three repeated manipulation and redemption loops. The lifecycle was:
FARM_USDC while the denominator is depressed and receive too many shares.The collected analysis quantifies the three profitable cycles:
Cycle 1: deposit 49,977,468.555526 USDC -> withdraw 50,298,684.215219 USDC
Cycle 2: deposit 50,276,170.498202 USDC -> withdraw 50,596,877.367825 USDC
Cycle 3: deposit 50,574,381.356760 USDC -> withdraw 50,894,567.817318 USDC
Those per-cycle gains are 321,215.659693, 320,706.869623, and 320,186.460558 USDC respectively, summing to the same 962,108.989874 USDC loss recorded in the vault balance diff. The trace also shows repeated calls into Curve and Harvest around these loops, while the auditor PoC trace shows repeated CRVStrategyStableMainnet::depositArbCheck() and calc_withdraw_one_coin(...) invocations during the exploit path, which is consistent with the stated breakpoint.
The direct victim was the Harvest FARM_USDC vault, with the strategy valuation path acting as the enabling component. The measured token loss in this transaction was:
{
"token_symbol": "USDC",
"amount": "962108989874",
"decimal": 6
}
This corresponds to 962,108.989874 USDC removed from the vault in one transaction. The exploit did not require privileged roles, governance control, or attacker-owned protocol infrastructure. It was an ACT opportunity realizable by any sufficiently prepared searcher with public chain data, public contract interfaces, and access to public flash liquidity.
0x35f8d2f572fceaac9288e5d462117850ef2694786992a8c3f6d02612277b0877, including sender, target contract, block number, and gas terms.FARM_USDC vault's -962,108.989874 USDC delta, the exploit contract's 691,781.898529 USDC residual, and the sender EOA's positive ETH delta after fees.VaultV1 implementation at 0x0de5f3a958f8e927c5b27d202d12b607e213d08c, which mints and burns shares against underlyingBalanceWithInvestment().CRVStrategyStableMainnet at 0xd55ada00494d96ce1029c201425249f9dfd216cc, which values invested underlying through underlyingValueFromYCrv() and the Curve convertor path.FARM_USDC proxy at 0xf0358e8c3cd5fa238a29301d0bea3d63a17bedbe.