Yearn V1 yDAI Curve 3pool Share-Price Manipulation (2021-02-04)

  • Name: Yearn V1 yDAI Curve 3pool share-price manipulation
  • Date: 2021-02-04
  • Protocol: Yearn Finance / yDAI v1 vault
  • Chain: Ethereum
  • Category: oracle manipulation / vault share-price manipulation / Curve 3pool imbalance extraction / strategy-routing slippage abuse
  • Loss: about $11M of yDAI vault deposits were lost before mitigation; Yearn estimated attacker profit at roughly 2.7M DAI to 2.8M DAI
  • Summary: The yDAI v1 attacker repeatedly shoved Curve’s 3pool into an imbalanced state, then forced Yearn’s yDAI vault to deposit DAI into that distorted pool and later unwind after the imbalance was partially reversed. In Yearn’s own example transaction, the attacker first minted 3Crv with 134M USDC and 36M DAI, withdrew 165M USDT to make USDT scarce, deposited DAI into yDAI so the vault’s strategy entered the pool at a bad rate, restored the pool with 165M USDT, withdrew from yDAI so the vault got back only about 92.3M DAI, then repeated the loop across 11 transactions. The result was not a stolen admin key or a broken vault invariant in isolation; it was a strategy path that kept honoring live 3pool imbalance as fair vault pricing while permissionless earn() calls, loose slippage limits, and a zero withdrawal fee made the loop profitable enough to keep running.
  • Trigger / entry point:
    • The exploited vault was Yearn’s v1 yDAI vault at 0xACd43E627e64355f1861cEC6d3a6688B31a6F952.
    • The relevant market state lived in Curve’s 3pool at 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7.
    • Because this was a v1 vault, the attacker could call earn() permissionlessly and push fresh vault deposits into the live strategy path at chosen moments.
    • Yearn’s postmortem says the vault’s slippage protection was set to 1%, the normal 0.5% withdrawal fee had been set to 0%, and both settings materially improved attack economics.
  • Root cause:
    • The yDAI v1 vault treated the current Curve 3pool exchange state as trustworthy enough for strategy deposits and withdrawals even when a single actor could violently skew that state with short-lived liquidity.
    • V1 architecture let the attacker decide when newly deposited DAI would be pushed into the strategy by calling earn() directly.
    • The slippage guard was too loose to reject the attacker-shaped pool state, and the temporary zero withdrawal fee let the attacker cycle the vault more cheaply.
    • In effect, Yearn let a flash-loan-scale pool imbalance decide how much real value the vault gave up when converting between DAI and 3Crv-related strategy exposure.
  • Exploit path:
    1. Yearn identified attacker contract 0x14ec0cd2acee4ce37260b925f74648127a889a28 after detecting a suspicious sequence of vault interactions around 21:45 UTC.
    2. In the representative exploit transaction 0xf6022012b73770e7e2177129e648980a82aab555f9ac88b8a9cda3ec44b30779, the attacker first minted 3Crv by depositing about 134M USDC and 36M DAI into Curve 3pool.
    3. They then withdrew about 165M USDT from 3pool, leaving the pool materially imbalanced.
    4. While that imbalance persisted, the attacker deposited DAI into the yDAI vault and triggered the vault to push that DAI into its strategy, which in turn deposited into the distorted 3pool at an unfavorable rate.
    5. The attacker next deposited about 165M USDT back into 3pool, partially restoring the balance.
    6. They withdrew DAI from yDAI; Yearn says the vault got back only about 92.3M DAI, while about 0.7M DAI of vault value remained stranded in 3pool during that cycle.
    7. The attacker then withdrew 165M USDT from 3pool again, re-opening the imbalance, and repeated the same deposit / rebalance / withdrawal pattern several times with smaller sizes.
    8. In the final leg of the example, instead of taking more USDT out, the attacker redeemed the original 3Crv position and withdrew about 134M USDC plus about 39.4M DAI, roughly 2.9M DAI more than the DAI leg they had started with.
    9. Yearn says this pattern was repeated across 11 exploit transactions over about 38 minutes until multisig signers disabled the vulnerable path.
  • What the attacker needed to be true:
    • Curve 3pool had to be deep enough to absorb attacker-sized stablecoin swings yet still imbalanced enough that Yearn’s strategy would trade at bad rates.
    • The vault had to keep treating those live pool conditions as valid strategy-entry and strategy-exit prices.
    • Permissionless earn() had to let the attacker decide when fresh deposits were forced into the imbalanced pool.
    • The 1% slippage limit and temporary 0% withdrawal fee had to leave enough room for repeated profitable loops.
    • The mitigation transaction had to arrive slower than the exploit loop.
  • Technical anatomy worth remembering:
    • This was a close cousin of Harvest, but the preserved lesson is slightly different: the attacker did not just mint vault shares at a discount, they used Yearn’s strategy-routing path itself to make the vault repeatedly buy into and unwind from a manipulated 3pool state.
    • The exploit is worth preserving because the dangerous oracle was not a separate price feed contract. It was the vault’s own assumption that current 3pool conditions were a fair conversion path for strategy accounting.
    • Permissionless earn() mattered. The attack was not only Curve got skewed; it was the attacker could choose the exact block where Yearn converted vault assets through that skewed market.
    • The incident is also a reminder that fee changes and migration-era UX concessions can widen an exploit window. Yearn’s own postmortem explicitly calls out the 0% withdrawal fee as part of why the loop was profitable.
  • Representative transactions and addresses:
    • yDAI v1 vault: 0xACd43E627e64355f1861cEC6d3a6688B31a6F952
    • Curve 3pool: 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7
    • Attacker contract used across the exploit sequence: 0x14ec0cd2acee4ce37260b925f74648127a889a28
    • Representative exploit transaction from Yearn’s disclosure: 0xf6022012b73770e7e2177129e648980a82aab555f9ac88b8a9cda3ec44b30779
    • Transaction first noticed by Yearn’s security team: 0x59faab5a1911618064f1ffa1e4649d85c99cfd9f0d64dcebbc1af7d7630da98b
    • Mitigation transaction setting setMin(0) on the DAI vault: 0x9875bec8588fe18facdb44bfa17a1fc396cd2f095f1426b8813e8cbc84302f72
    • Follow-up mitigation transaction for the other stablecoin v1 vaults: 0x8035321e1cfceefea464121fe8ed41ee79fef2616f866ef9acc911b4584714d0
  • Response / mitigation:
    • Yearn’s multisig set setMin(0) on the yDAI vault, which disabled further strategy deposits and stopped the exploit while it was underway.
    • As a precaution, the same mitigation was then applied to the USDC, USDT, and TUSD v1 vaults.
    • Public reporting after the incident noted that about 24M DAI of the vault’s roughly 35M DAI was saved because the team interrupted the loop quickly.
    • Yearn later used treasury-backed financing to make vault users whole rather than leaving the loss socialized inside the deprecated v1 vault.

Pattern tags

Why the exploit worked

  • Yearn’s yDAI v1 vault never separated current Curve execution conditions from vault accounting truth. Once the attacker made USDT scarce in 3pool, the vault still treated that skewed route as fair enough for depositing DAI into strategy exposure and later unwinding back out.
  • The attacker did not need to corrupt a standalone oracle contract. They only needed the vault to keep believing that the live 3pool conversion path was a money-good valuation and execution surface for strategy accounting.
  • Permissionless earn() made timing part of the exploit surface. The attacker could decide the exact block where fresh DAI would be pushed into the manipulated pool, so the vault internalized the attacker-authored imbalance instead of waiting for a keeper, delayed snapshot, or healthier market state.
  • Loose slippage and the temporary 0% withdrawal fee turned a fragile accounting seam into a repeatable profit loop. Yearn’s own disclosure is clear that the attack only worked economically because the vault tolerated sufficiently bad entry / exit conditions and let the attacker cycle them cheaply across 11 transactions.
  • The durable lesson is sharper than Curve was manipulable: Yearn fused strategy-entry timing, manipulated pool state, and vault share-value realization into one same-window economic object even though the attacker could author the first piece and then partially normalize it before the vault finished paying out.

Detection and audit pivots

  • Treat public maintenance verbs like earn() as oracle-timing surfaces. Ask not only can someone call it? but can someone skew the venue first, then force the vault to consume that skew as strategy-entry truth?
  • Rehearse the actual attack order: imbalance the shared pool, deposit into the vault, force strategy entry, partially restore the pool, then withdraw. Reviews that only test deposit pricing or only test withdrawal accounting will miss the full round-trip seam.
  • Compare strategy-entry and strategy-exit pricing against realizable value at the protocol’s real operating size. If the vault can only defend its mark while the manipulated 3pool state persists, then the mark is not durable vault truth.
  • Audit fee and slippage changes as part of the security boundary, not just UX tuning. Yearn’s 1% slippage tolerance and temporary zero withdrawal fee materially widened the attack window even though neither knob looked like an oracle module in isolation.
  • Check whether delayed publication, guarded strategy entry, or fresh-mark quarantine would kill profitability. If a simple delay between pool-state observation and vault accounting breaks the loop, the protocol is over-crediting same-window execution conditions.

Failure-prevention checklist

  • Remove or heavily constrain public maintenance verbs like earn() when they can force fresh deposits into live strategy execution. If public callers can choose the exact block where a distorted venue becomes vault strategy truth, they own timing authority over solvency.
  • Separate strategy-entry execution from immediate share-accounting authority. A vault should not let one attacker-authored pool state decide when deposits are invested and then let later withdrawals settle as if the same state had been durable fair value.
  • Tighten slippage and imbalance controls around strategy routes that touch shared AMMs. A 1% tolerance is already dangerous if the protocol can be cycled repeatedly through the same manipulated venue.
  • Quarantine fresh strategy marks before they create full withdrawal rights. Delayed settlement, delayed share claims, staged earn() windows, or shadow pricing lanes all help when the exploit depends on same-window pool distortion becoming permanent vault loss.
  • Keep fee-policy changes inside the threat model. Temporary 0% withdrawal fees and migration-era UX concessions should be reviewed as part of exploit economics, not as harmless product tuning.
  • Force manipulated strategy paths to realize their own unwind cost. If a shared pool authored the bad execution state, users should not be able to route losses onto a stronger vault balance sheet or cleaner later mark without carrying that state through redemption semantics.
  • Monitor strategy-entry timing concentration. Repeated deposits followed immediately by earn() calls during abnormal pool imbalance should trip degraded mode faster than ordinary price-band alarms.
  • Treat strategy-route dependence as oracle dependence even without a dedicated oracle contract. Any live venue state that decides how much value the vault sends into or gets back from strategy is already a solvency-critical pricing surface.
  • Add imbalance-aware degraded modes near the strategy boundary: pause earn(), narrow withdrawals, or require slower operator-controlled deployment when pool composition moves outside realistic organic ranges.
  • Preserve one share-truth object across deposit timing, strategy execution, and withdrawal semantics. If manipulated entry conditions and healthier exit conditions can both author the same vault share in quick succession, the vault is over-trusting transient market state.

Audit prompts

  • Who can trigger strategy deployment, harvest, rebalance, or earn()-style verbs, and can that trigger be timed around a manipulated market state?
  • What exact venue state does the vault trust when it turns idle deposits into strategy exposure, and how quickly can an attacker distort and then normalize that state?
  • If the pool route is skewed for one block, what stops the vault from investing fresh capital at that bad rate and later honoring withdrawals against a cleaner mark?
  • Are deposit timing, strategy-entry timing, and withdrawal pricing all describing the same economic object, or can an attacker choose the first and benefit from a better later version of the second?
  • How much per-cycle distortion is tolerated, and how many profitable sub-threshold cycles fit inside one operational response window?
  • Which UX or migration knobs change exploit profitability materially: withdrawal fees, strategy thresholds, public keepers, idle-buffer policy, or batch timing?
  • If earn() were delayed by one block, one keeper cycle, or one explicit commit/claim stage, would the exploit still work? If not, the vault is probably over-crediting same-window execution state.
  • Does the vault ever use live strategy-route quotes as if they were reserve truth, even though the route could not clear at that size without attacker-authored slippage?
  • What monitoring ties abnormal pool imbalance directly to vault actions, rather than treating market-state alerts and vault-operation alerts as separate systems?
  • Which module actually owns the security boundary here: the vault, the strategy, the shared AMM, or the maintenance verb that decides when the vault must trust the AMM?

Lessons that should already be standard

  • Public strategy-trigger verbs are not harmless convenience features once they can force fresh deposits into manipulated market conditions.
  • Shared-pool execution state is oracle state when it determines how much real value a vault gives up or gets back.
  • Same-window timing control can be the decisive exploit edge even when deposit and withdrawal math look locally correct.
  • Migration-era fee waivers and relaxed safety knobs are part of the attack surface if they improve loop economics.
  • A vault is unsafe when strategy-entry timing, share-accounting truth, and withdrawal value are allowed to describe different market states in one attacker-controlled sequence.
  • Delays, staging, and slower claim semantics are sometimes the cleanest fix; they keep one transient pool distortion from becoming permanent vault loss.
  • The right healthy-side question is not only was Curve manipulable? but why was a permissionless caller allowed to decide exactly when Curve's manipulated state became vault truth?

Why this incident matters

  • It is an early, clean example of a yield vault’s strategy path functioning as an oracle-manipulation surface.
  • It preserves the distinct permissionless strategy trigger + imbalanced pool execution + loose slippage + no withdrawal fee variant rather than collapsing Yearn into Harvest’s more familiar deposit-cheap / redeem-dear story.
  • It also helped push the ecosystem away from v1-style anyone can force strategy deployment right now assumptions in vault design.
  • It is a good companion to Value because the vault loss again came from execution-path accounting rather than a standalone price feed, but here the decisive seam was attacker-chosen strategy timing rather than hypothetical controller-side unwind math.

Internal linkages

Control surface

  • The leverage sat in v1 earn() permissions, Curve 3pool execution quality, slippage configuration, withdrawal-fee policy, and the vault’s willingness to route strategy capital through a market whose current state the attacker could define.
  • Yearn did not mainly fail because Curve was volatile. It failed because the vault kept honoring attacker-shaped pool imbalance as if it were fair strategy pricing, and let the attacker choose exactly when that pricing would be consumed.
  • The preserved healthy boundary was that strategy-entry timing, share-accounting truth, and eventual withdrawal value should have remained one bounded object rather than being joined only by attacker-controlled 3pool state.

Sources

Last reviewed

  • 2026-07-20 UTC