Lesson 7 — Oracle and price manipulation: flash loans against TWAPs
When a lending or derivatives protocol asks 'what's the price of X?', the answer can be manipulated. Today: how price oracle attacks work, why spot prices from a single AMM are deadly, and what makes a robust oracle.
The single largest category of DeFi exploit by total dollars lost is price-oracle manipulation. The protocol asks an oracle for a token's price, makes a financial decision based on that answer (issue a loan, mark-to-market a derivative, distribute rewards), and the attacker has corrupted the oracle's view in their favour. Mango Markets, Harvest Finance, Inverse Finance, Cream Finance, bZx, Compound proposal 64, and many more — all the same bug class.
**The naive design: spot price from a single AMM.** A protocol needs to price token X in USD. It calls `getReserves()` on the X/USDC Uniswap V2 pool and computes `price = reservesUSDC / reservesX`. The bug: anyone with capital can move that ratio temporarily. An attacker borrows a large amount of USDC via flash loan, swaps it for X (driving the price up), uses the inflated price to borrow more X-collateralised value than they could legitimately, exits, repays the flash loan from the borrowed value. Net profit: the gap between the inflated oracle price and reality. Spot price from a single pool is unsafe.
**Time-weighted average prices (TWAPs).** Uniswap V2 includes a cumulative-price accumulator that lets contracts compute a TWAP over a chosen window. A 30-minute TWAP is much harder to manipulate than spot — moving the average by N% requires the attacker to either hold the manipulated price for 30 minutes (capital-cost prohibitive) or move it by enormous N during a portion of the window. Uniswap V3 adds a more efficient TWAP with arbitrary windows. TWAPs are the minimum defence; they're not a complete one — long-window TWAPs lag real moves and create their own liquidation-pricing problems.
**Cross-pool / cross-DEX manipulation.** A TWAP from a single pool can still be manipulated by an attacker willing to spend capital across the window. The defence is to use multiple pools / DEXes / sources and aggregate. Chainlink's price feeds aggregate multiple off-chain market-data sources and post the median. Pyth uses publisher-aggregated prices with explicit confidence intervals. Both are substantially harder to manipulate than any single-pool oracle.
**The Mango Markets exploit (October 2022).** Avraham Eisenberg's $117M exploit: Mango's perpetuals platform priced MNGO from on-chain DEX trading. Eisenberg used $5M to push the MNGO price up by ~1000% within a window, used the inflated mark price to borrow $117M of other assets against the MNGO collateral, and exited. The 'attack' was deemed legal-ish at first because the price moves were genuine market trades — he later negotiated a partial return, then was charged criminally and convicted in 2024. The contract was 'correct' under its design; the design assumed market prices weren't manipulable, which the attacker proved wrong.
**The Inverse Finance / Cream Finance / bZx pattern.** Multiple protocols lost funds to the same pattern: lending against a collateral asset priced from a single AMM, attacker manipulates the AMM, borrows the inflated value, exits. The defence is well-known (TWAP from multiple sources, conservative LTV limits, circuit breakers on rapid price moves) but the bug class continues to appear because adopting safer oracles costs gas and complexity.
**Validation patterns.** A defensive oracle integration includes: (1) **Staleness check** — reject prices older than N minutes (Chainlink reports a last-update timestamp). (2) **Deviation circuit breaker** — if the new price differs from the previous by more than X%, halt operations and require manual review. (3) **Heartbeat enforcement** — require the oracle to update at minimum frequency; if it doesn't, pause. (4) **Sanity-bound checks** — reject prices outside a plausible range. None of these eliminate manipulation but each makes attacks harder and slower.
**The honest framing.** Even the best on-chain oracle is not infallible — Chainlink has had bugs, Pyth has had incident reports. The right framing for protocol design is *defence in depth*: oracles, conservative LTVs, slow-moving accounting (no liquidations on a single bad tick), circuit breakers, and emergency pause governance. Protocols that rely on a single oracle source are taking concentrated counterparty risk regardless of the source's reputation.
Example
A worked example of a flash-loan oracle attack. Step 1: Attacker observes that protocol P prices token X using spot reserves of the X/USDC Uniswap V2 pool, and that protocol P will issue a USDC loan worth 75% of any X collateral's USDC value. Step 2: Attacker takes a $10M USDC flash loan from Aave. Step 3: Attacker swaps $9M USDC for X in the X/USDC Uniswap pool, pushing X's spot price from $1 to $10. Step 4: Attacker deposits 100,000 X tokens as collateral in protocol P; protocol P queries the oracle (now reading $10/X), values the collateral at $1M, and issues a $750K USDC loan against it. Step 5: Attacker repeats the loan operation against multiple of P's collateral pairs, harvesting a total of $5M in USDC. Step 6: Attacker swaps a small portion of remaining X back to USDC (pool resets toward $1), repays the $10M flash loan, walks away with $5M minus gas. Mitigation: P should use a 30-min Uniswap V3 TWAP at minimum, and ideally a Chainlink or Pyth feed for a high-value asset. Cost: more gas, lag in liquidations. Benefit: this specific exploit becomes infeasible.
Common mistakes
- Pricing assets from a single AMM's spot reserves. The default oracle bug.
- Pricing from a TWAP without aggregating multiple sources. A well-capitalised attacker can still move a single-pool TWAP.
- Forgetting Chainlink's staleness timestamp. A stalled oracle isn't safer than a manipulated one; it's a different bug.
- Allowing instant liquidations off a single price tick. Defence in depth means accumulating evidence before consequential actions.
- Trusting any oracle to be infallible. Even Chainlink has had incidents; design for partial failure.
Check your understanding
A lending protocol prices a thinly-traded ERC-20 collateral asset from the spot reserves of its main Uniswap V2 pool. What is the architectural bug?
Key terms covered
Sources & further reading
- Primary
- Primary
- Primary
- Secondary
We prioritise primary sources. Where a topic moves quickly (regulation, security incidents), we re-check sources on the cadence shown by the page's "Next review" date.