📋 What Is It?
Price Oracle Manipulation occurs when a contract makes a financial decision - how much to lend, mint, redeem, or liquidate - based on a price read from a source an attacker can move within the same transaction. Nothing in the contract's own logic is "buggy"; the flaw is trusting a manipulable number. A DEX pool's reserves, a swap quote, or a token balance all reflect instantaneous market state, and a flash loan lets anyone move that state risk-free and atomically. The attacker distorts the price, trades against the contract while it reads the distorted value, and repays the loan in the same block.
⚠️ Common Exploits
- Spot Reserves: Price derived from
getReserves()of one pool - Swap Quotes:
getAmountsOut()used as a price feed - balanceOf Valuation: LP/share value from raw pool balances
- Single Source: One venue with no independent cross-check
- Stale Feed:
latestRoundDataused without a freshness check - No Sanity Bounds: A 90% price swing accepted as truth
- Flash-Loan Skew: Manipulate-borrow-repay in one atomic tx
🔴 Attack Flow
↓
2. Swap heavily to skew the target pool's price
↓
3. Victim reads the distorted spot price
↓
4. Borrow / mint / redeem against the fake value
↓
5. IMPACT: Repay loan, keep the difference - pool drained!
❌ Vulnerable Code
✅ Secure Code
✓ Prevention Checklist
- Use robust decentralized feeds (Chainlink), not spot reads
- Check
updatedAtfreshness on every feed read - Reject non-positive answers and incomplete rounds
- Use a TWAP for any on-chain source you must read
- Cross-check multiple independent sources
- Enforce deviation and min/max sanity bounds
- Never price from
balanceOfor raw reserves - Value LP tokens via fair-value formula, not live balances
- Add circuit breakers, pauses, and per-block rate limits
- Assume unlimited flash-loaned capital in the threat model
- Fork-test the pricing path under a simulated flash loan
🔍 Detection & Tools
Analysis Tools:
Oracles & Infra:
How to Test:
- Fork-test: flash-loan, skew the pool, call the victim function
- Assert the protocol does NOT over-lend / mis-mint / mis-liquidate
- Fuzz/invariant: no one-tx sequence extracts more than deposited
- Grep pricing paths for
getReserves,getAmountsOut,balanceOf - Monitor: feed staleness, large single-tx swaps in priced pools
🌍 Real-World
- Flash-loan collateral mispricing (bZx / Harvest class): A lending or vault protocol priced an asset from a DEX pool's spot state; an attacker flash-loaned, skewed the pool, then borrowed or redeemed against the inflated valuation, leaving bad debt for honest depositors.
- LP-token / balanceOf mispricing class: A protocol valued LP-token collateral from live pool balances; an attacker inflated those balances within the transaction and borrowed against value that did not exist.
- Stale / single-source feed failure: A protocol relied on one source with no freshness check or fallback; trades and liquidations executed against a price that no longer matched the market.
- Enabling factor: In each class the root cause is trusting a manipulable price; flash-loan atomicity turns "expensive to move" into "free to move."
📌 Quick Tips
- DO NOT use
getReserves/getAmountsOutas a price - DO NOT value shares/LP tokens by
balanceOf - DO NOT trust a feed without a freshness check
- DO use decentralized feeds and TWAPs
- DO cross-check sources and bound deviation
- DO design for unlimited atomic capital
- DO add circuit breakers and rate limits