Inverse Finance INV / Keep3r Oracle Manipulation (2022-04-02)

  • Name: Inverse Finance INV / Keep3r oracle manipulation
  • Date: 2022-04-02
  • Protocol: Inverse Finance Anchor
  • Chain: Ethereum
  • Category: oracle manipulation / thin-liquidity collateral inflation / same-block TWAP capture / undercollateralized borrow
  • Loss: about $15.6M, including roughly 3,999,669 DOLA, 1,588 ETH, 94 WBTC, and 39 YFI
  • Summary: The attacker used about 500 ETH of self-funded capital to push INV price violently higher on thin SushiSwap liquidity, then forced Inverse Finance’s Keep3rV2Oracle to record that distorted state in block 14506358. In the next block, before the oracle window had meaningfully aged and before arbitrage could fully protect Anchor, the attacker converted the acquired INV into roughly 1,746 xINV collateral at the manipulated mark and borrowed out deep-liquidity assets worth about $15.6M. The exploit was not just single-oracle risk; it was a balance-sheet design failure where a thin governance token, a same-venue oracle, and a one-block timing quirk turned a briefly printable price into real borrow power.
  • Trigger / entry point:
    • Anchor let INV-derived collateral back large borrows of DOLA, ETH, WBTC, and YFI.
    • Inverse relied on a Keep3rV2Oracle path tied to a thin SushiSwap INV market.
    • The attacker could first force the oracle to checkpoint manipulated cumulative prices with workForFree() and then borrow in the next block while the oracle still reflected the attacker’s printed state.
  • Root cause:
    • Inverse put a thin INV market too close to its solvency core: a short-window, single-venue oracle decided how much hard collateral value Anchor would recognize.
    • The Keep3rV2Oracle path was supposed to behave like a TWAP, but under the exploit timing it effectively let the attacker carry forward the manipulated last-block price into the next block’s solvency check.
    • CertiK and Inspex both highlighted the same structural issue from different angles: manipulated Sushi cumulative price data was written into oracle observations, then current() / _computeAmountOut() style logic used a tiny elapsed interval so the protocol still read the bad mark when the borrow transaction landed.
    • The real failure was not merely oracle freshness; it was that Inverse let a thin, governance-token mark become immediate borrowing capacity against much deeper reserve assets.
  • Exploit path:
    1. The attacker prepared capital from Tornado Cash-linked funding and deployed exploit contract 0xea0c959bbb7476ddd6cd4204bdee82b790aa1562.
    2. In preparation transaction 0x20a6dcff06a791a7f8be9f423053ce8caee3f9eecc31df32445fc98d4ccd8365 in block 14506358, the attacker swapped about 300 WETH for about 374.385 INV on the thin Sushi INV/WETH pool, sharply repricing INV.
    3. In the same preparation sequence, the attacker swapped about 200 WETH into about 690,307 USDC, converted that to about 690,203 DOLA on Curve, then bought about 1,372.052 INV on the Sushi INV/DOLA pair.
    4. The attacker called workForFree() so Keep3rV2Oracle contract 0x39b1df026010b5aea781f90542ee19e900f2db15 would store manipulated cumulative-price observations for the INV market.
    5. In the next block, borrow transaction 0x600373f67521324c8068cfd025f121a0843d57ec813411661b07edc5ff781842 landed while the oracle still reflected the manipulated prior-block state. The attacker also called sync() to ensure the pair’s cumulative-price data had advanced into the new block.
    6. Using the INV acquired in the preparation stage, the attacker deposited the position and minted roughly 1,746 xINV, which Anchor then treated as borrowable collateral through the manipulated INV pricing path.
    7. Anchor’s pricing path returned an INV-derived collateral value around $20,926 per unit, letting the attacker treat the position as tens of millions of dollars of borrowing power despite a fair value closer to the low hundreds of thousands.
    8. Against that fake solvency, the attacker borrowed about 3,999,669 DOLA, 1,588 ETH, 94 WBTC, and 39 YFI, then moved the assets onward to an externally owned address and later through Tornado Cash.
  • What the attacker needed to be true:
    • Sushi INV liquidity had to be thin enough that a few hundred ETH could move the oracle market by orders of magnitude.
    • Inverse had to rely on that same market, through Keep3r, for solvency-critical collateral pricing.
    • The attacker had to be able to force an oracle update in one block and then exploit the borrow path in the next block before the manipulated state aged out or was overwritten.
    • Anchor had to offer much deeper and higher-quality borrowable assets than the market depth backing INV itself.
  • Technical anatomy worth remembering:
    • This was not a flash-loan spot-oracle attack in the narrow textbook sense. The attacker used self-funded capital and cross-block execution discipline because the oracle path made one manipulated block enough.
    • The exploit is a good reminder that TWAP is not a magic defense. A TWAP implementation can still fail if update cadence, checkpointing rules, and read paths let a single manipulated interval dominate the value actually used for collateral checks.
    • The attacker printed the price on one thin market and withdrew value from a different, much deeper balance sheet. That two-market structure is the real anatomy to preserve.
    • The collateral asset was especially dangerous because it was protocol-adjacent governance inventory. INV did not need deep, executable liquidity to unlock blue-chip borrow capacity; it only needed to look expensive to the oracle long enough.
    • This incident was also notably MEV-aware: contemporaneous analysis highlighted private/bundled submission and transaction spam to win the exact block timing needed for the stale-yet-accepted oracle state.
  • Representative transactions and addresses:
    • Preparation / manipulation / oracle-update transaction: 0x20a6dcff06a791a7f8be9f423053ce8caee3f9eecc31df32445fc98d4ccd8365
    • Borrow transaction: 0x600373f67521324c8068cfd025f121a0843d57ec813411661b07edc5ff781842
    • Exploit contract: 0xea0c959bbb7476ddd6cd4204bdee82b790aa1562
    • Exploiter address 1: 0x117c0391b3483e32aa665b5ecb2cc539669ea7e9
    • Exploiter address 2: 0x8b4c1083cd6aef062298e1fa900df9832c8351b3
    • Oracle contract highlighted in incident analyses: 0x39b1df026010b5aea781f90542ee19e900f2db15
    • Oracle update function highlighted in incident analyses: workForFree()
  • Response / mitigation:
    • Inverse paused borrowing on Anchor after the exploit.
    • The team said it would work with Chainlink on a new INV oracle and proposed making affected users whole through DAO processes.
    • The deeper lesson is that replacing one feed with another is only part of the fix. Thin collateral also needs stricter haircuts, borrow caps, and design skepticism about whether a governance token should sit in the solvency core at all.

Three oracle-authority promotions this incident collapsed

1. A thin Sushi INV quote could still be printed

  • The exploitable starting fact was only that the attacker could author one extreme INV/WETH state on a pool with about 432 INV and 46 ETH of liquidity before the manipulation leg, then push that pool into a radically different reserve picture with a few hundred ETH.
  • That thin-market authorship was then staged deliberately across blocks rather than atomically: the attacker first shaped the INV price in block 14506358, then used workForFree() to make Keep3r persist observations derived from that manipulated cumulative-price state.
  • In other words, the first dangerous promotion was not yet Anchor now owes money; it was only one attacker-shaped Sushi interval now exists and the oracle machinery has been nudged to notice it.

2. Anchor still promoted that printed interval into canonical xINV collateral truth

  • The decisive second promotion was that Inverse’s oracle path still treated the just-authored interval as if it were acceptable collateral truth one block later.
  • Inspex’s reconstruction and CertiK’s analysis preserve the same core boundary from opposite angles: workForFree() stored the manipulated observation at block 14506358, then in block 14506359 the oracle read path still returned the last-block manipulated price because the tiny elapsed interval effectively let the printed state survive as the next block’s current() answer.
  • That was the moment the protocol crossed from bad quote exists to bad quote counts as money-good solvency input: roughly 1,746.437878752304088448 xINV was accepted around the manipulated ~$20,926 mark, creating about $36.5M of notional collateral value and about $21.9M of borrowable capacity at the 60% collateral factor.

3. That published truth still inherited immediate reserve authority

  • The final promotion was that Anchor did not merely display or checkpoint the manipulated INV value; it still let that published mark authorize immediate borrowing against deeper reserves in the very next step.
  • Against the printed xINV collateral truth, the attacker withdrew about 3,999,669.029654761043260989 DOLA, 1,588.263719446159096974 ETH, 94.03071805 WBTC, and 39.368440899328442 YFI before the system could reclassify the mark as too fresh, too thin, or too attacker-authored for full credit authority.
  • That is the reusable design split worth preserving: a thin quote can be printed, that quote becomes canonical collateral truth, and that accepted truth still deserves immediate reserve-spend authority were three different promotions, and Inverse collapsed them into one short cross-block oracle window.

Pattern tags

  • oracle-manipulation
  • protocol-native-collateral-fragility
  • One attacker-shaped Sushi block only became deep-asset borrowing authority because Keep3r’s checkpoint / read cadence let the manipulated interval survive into the next block’s solvency checks
  • TWAP language obscured the real boundary: Inverse was still willing to honor effectively same-window thin-market state as if it were durable collateral truth
  • Protocol-adjacent INV inventory sat close enough to the solvency core that a briefly printed governance-token mark could monetize against DOLA, ETH, WBTC, and YFI reserves

Why the exploit worked

  • The exploiter did not need to sustain a long-lived fair-value story for INV; they only needed one block where thin Sushi liquidity could be pushed high enough for Keep3r to checkpoint manipulated cumulative prices, then one follow-on block where Anchor still treated that checkpoint as fresh collateral truth. The exploit window existed because publication timing and collateral authority were too tightly coupled.
  • Contemporary analyses converge on the same timing seam. CertiK emphasized that the attacker first forced workForFree() to commit manipulated observations, while Inspex highlighted how the later current() / _computeAmountOut() path still honored that observation over a very short elapsed interval. In practice, the system’s TWAP wrapper did not buy enough time separation to stop one extreme block from becoming borrow power.
  • INV’s role as governance-adjacent, low-float collateral made the balance-sheet side worse. Anchor was willing to lend blue-chip reserves against a token whose executable exit depth was nowhere near the value the manipulated oracle temporarily recognized.
  • This means the decisive failure was not merely single venue bad; it was same-window published thin-market truth became immediate reserve authority while the collateral itself should already have faced stronger skepticism and tighter downstream quarantine.
  • The MEV-aware execution details matter because they show how narrow the exploitable seam was. Once the protocol allowed manipulate -> checkpoint -> borrow next block, private ordering and timing discipline were enough to turn a short-lived oracle artifact into permanent reserve loss.

Detection and audit pivots

  • Ask every TWAP oracle what minimum elapsed time, observation spacing, and publication delay it actually relies on before a new mark deserves collateral authority. If one manipulated block can still dominate the next block’s borrow decision, the system is not meaningfully quarantining fresh state.
  • Review update permissions and checkpoint helpers like workForFree() as part of the solvency surface, not just as oracle liveness plumbing. If an attacker can choose when the oracle snapshots a thin market, they may also be choosing when collateral truth gets minted.
  • Stress-test house asset or governance token as collateral separately from generic volatile collateral. Inverse is a clean reminder that even a more sophisticated read path does not rescue a market whose executable exit depth is tiny relative to what the lending system will release against it.
  • Check whether published oracle state and downstream borrowing rights narrow independently. If the protocol can still read and display a fresh mark, but cannot yet lend large reserves against it, the exploit path gets much harder.
  • Simulate manipulate this block, consume next block rather than only same-transaction flash-loan paths. Some of the most dangerous oracle windows are not atomic; they are one short staging step away.

Why this incident matters

  • It is a clean exemplar of thin-collateral oracle manipulation in a lending market, distinct from LP-wrapper collateral attacks like Cheese Bank and from perp-PnL inflation attacks like Mango.
  • It shows how a protocol can say we use TWAP and still be exploitable if the update/read mechanics let the attacker checkpoint an extreme price and cash it out one block later.
  • It is also a strong reminder that governance tokens and low-float house assets should be treated as suspect collateral even when the pricing code looks more sophisticated than a raw spot read.
  • It also preserves a narrower timing lesson the corpus needs in public: one attacker-shaped block of thin-market state should not have been allowed to graduate into immediate blue-chip borrowing authority just because the next block’s oracle read still called it a TWAP.

Failure-prevention checklist

  • Treat oracle publication timing and collateral authority as one control surface. A newly checkpointed mark from a thin venue should not become immediate borrow power in the same block or the next block without a meaningful aging or quarantine interval.
  • Inventory who can force, sponsor, or accelerate oracle checkpoints such as workForFree(), then review those functions as solvency-critical entrypoints rather than harmless liveness helpers.
  • Apply collateral factors, borrow caps, and per-market reserve limits based on executable depth and unwindability, not just on whether a governance token has a live DEX price and a nominal TWAP wrapper.
  • Quarantine protocol-native and governance-adjacent collateral separately from generic volatile assets. Thin house assets should start with smaller caps, delayed borrow enablement, and stricter downgrade rules when oracle confidence weakens.
  • Keep the venue that prints collateral truth meaningfully independent from the deepest reserves the protocol will release against that truth. If a few hundred ETH can move the price but tens of millions in blue-chip assets can be borrowed, the balance sheet is over-trusting the quote.
  • Require real chronology separation in oracle design. Current reads, cumulative-price checkpoints, and borrow-path consumption should not let one attacker-shaped interval dominate the very next solvency decision.
  • Add automatic degraded-mode responses for thin-market shocks: pause fresh borrowing, tighten collateral factors, cap withdrawals, or isolate the market when price moves exceed plausible depth-backed ranges.
  • Simulate cross-block attacks explicitly. Test manipulate this block -> force checkpoint -> consume next block rather than assuming only atomic same-transaction oracle abuse matters.
  • Separate display marks from credit marks. A value suitable for UI, analytics, or soft warnings is not automatically safe to mint DOLA, ETH, WBTC, and YFI borrowing capacity.
  • Re-review collateral policy whenever oracle plumbing changes. Replacing one feed with another is not a full fix if the asset still lacks depth commensurate with the reserves it can unlock.

Audit prompts

  • What minimum elapsed time, observation spacing, and publication delay must pass before a newly printed price is allowed to create borrow power?
  • Can any user or keeper choose when a thin market is snapshotted into solvency-critical oracle state, and if so, what prevents them from pairing that timing power with a manipulation trade?
  • If the attacker prints the collateral mark on one venue today, how much higher-quality inventory can they borrow out elsewhere before the protocol has time to downgrade or quarantine the asset?
  • Does the protocol treat protocol-native or governance-token collateral as a special risk class, or does it inherit generic collateral factors copied from deeper assets?
  • Where exactly does the system distinguish oracle value available from oracle value trusted for full borrowing authority?
  • Can a one-block or one-interval distortion still dominate the next block’s collateral check even though the implementation is described as a TWAP?
  • If the primary oracle venue is thin, what independent market-depth or reserve-liquidity evidence limits the amount of DOLA, ETH, WBTC, or YFI that can be borrowed against it?
  • Which functions, keeper paths, or governance actions can refresh oracle state, and are those pathways included in adversarial timing reviews?
  • During a violent repricing of thin collateral, what permissions shrink automatically: fresh borrowing, collateral factor, reserve outflow, liquidation parameters, or market isolation?
  • If the protocol had to liquidate the printed collateral position at size immediately after the borrow, how much value would it really recover versus what the borrow engine credited?

Lessons that should already be standard

  • TWAP is not a synonym for manipulation resistance. If one attacker-shaped interval can still become next-block borrow authority, the protocol has time-averaged a thin market without making it trustworthy.
  • Oracle update helpers are credit controls when they decide when manipulated state becomes official. Treating them as mere liveness plumbing hides a real solvency surface.
  • Governance tokens and protocol-adjacent inventory are not ordinary collateral just because they trade somewhere. Reflexive confidence and thin exit depth make them especially dangerous reserve backstops.
  • A printed price only becomes a theft path when the protocol honors it for something deeper. The key design failure is not bad INV mark; it is bad INV mark instantly unlocks DOLA, ETH, WBTC, and YFI.
  • Cross-block timing windows matter. Many oracle exploits are not atomic flash-loan stunts; they are short staging sequences where publication timing and borrow authority are still too close together.
  • Oracle hardening is partly a collateral-policy problem. Safer feeds help, but delayed authority, tighter caps, and thin-collateral quarantine are what stop a temporary price from becoming permanent loss.
  • The right review question is not only can this market be manipulated? but if it is manipulated once, what real reserves can leave before the system can say no?

Internal linkages

Control surface

  • The leverage sat in collateral admission for INV-derived assets, Keep3rV2Oracle checkpoint and read semantics, oracle venue choice, oracle update permissions, borrow-cap policy, and the protocol’s willingness to lend deep reserves against a thin governance-token market.
  • Inverse did not merely have a bad price feed. It had a joined timing-and-solvency failure: a one-block printed INV mark became next-block money-good collateral against the rest of Anchor.

Sources

Last reviewed

  • 2026-08-02 UTC