Oracle manipulation vulnerabilities in disclosed bug bounty reports
When a protocol trusts a price it cannot defend, an attacker moves the price instead of attacking the protocol.
- Reports indexed
- 152
- Total paid
- $900k
- Critical
- 1
- Largest payout
- $900k
Oracle manipulation is rarely a bug in the oracle. It is a bug in what the consuming protocol is willing to believe. A lending market that reads a spot price from a thin pool, a vault that values its own LP token by calling the pool it is inside of, a liquidation engine that never checks how old a Chainlink round is — all of these are sound contracts fed bad numbers.
The payouts in this class cluster around two mistakes. The first is using an instantaneous value where a time-weighted or multi-source value belongs. The second is failing every safety rail the oracle already provides: unchecked staleness, ignored round completeness, no deviation bound, and no fallback when the primary feed reverts.
Because oracle bugs are about integration rather than implementation, they surface disproportionately in reports against lending protocols and structured-product vaults built on top of otherwise well-audited primitives.
What reviewers look for
- Spot reserves or `getAmountsOut` used as a price source
- Missing staleness, round-completeness or deviation checks on a push feed
- LP token valuation derived from the pool's own current reserves
- A single feed with no fallback and no circuit breaker
- Prices sourced from a pool shallow enough to move within one transaction
Curated highlights
The largest disclosed payouts in this group, with our own summary of each. Every report links back to the original disclosure.
Spot TWAP oracle manipulated via single-block flash loan
A perpetual derivatives protocol relied on a Uniswap V3 TWAP oracle whose pool observation cardinality was capped at 12, severely reducing its intended 30-second time-weighted average window. An attacker executed a single-block flash loan to heavily distort the underlying spot price without triggering any secondary price feed validation. This allowed the attacker to open oversized leveraged positions at an artificial mark price and force liquidations against counterparties in a single atomic transaction.
Good Entry: Incorrect Solidity version in FullMath.sol can cause permanent freezing of assets for arithmetic underflow-induced revert
Good Entry ported Uniswap v3's FullMath.sol into its TokenisableRange code but under a Solidity ^0.8.4 pragma instead of the original pre-0.8 unchecked-arithmetic pragma, which silently turns its intermediate subtractions into checked, reverting operations. As a result, LiquidityAmounts.getAmountsForLiquidity reverts on underflow whenever the pool's market sqrt price ratio falls below a range position's lower tick, a condition the author demonstrates with real mainnet prices and argues can be permanent when one asset keeps appreciating. Since that helper feeds returnExpectedBalance and the deposit/withdrawal paths of range positions, affected users can be locked out of their funds. The sponsor confirmed the faulty library version and replaced it with the correct Uniswap v3 0.8-branch libraries, with the mitigation verified in a follow-up audit.
Good Entry: Overflow can still happen when calculating `priceX8` inside `poolMatchesOracle` operation
Good Entry's GeVault compares a Uniswap v3 pool price against a Chainlink oracle inside poolMatchesOracle to decide whether a rebalance should occur. The computed priceX8 value derives from the pool's sqrtPriceX96, and the code pre-scales it by only 2**12 before squaring, which is insufficient to prevent the intermediate multiplication from overflowing the uint accumulator. Using live WBTC/WETH pool data, the researcher reproduces an arithmetic over/underflow revert that breaks the price comparison and therefore the rebalance path. The sponsor confirmed the finding and shipped a fix that rescales the price using the Uniswap v3 OracleLibrary convention, with the mitigation later confirmed in a follow-up audit.
Good Entry: TokenisableRange's incorrect accounting of non-reinvested fees in "deposit" exposes the fees to a flash-loan attack
Good Entry's TokenisableRange wraps Uniswap V3 positions and attempts to claw back accumulated trading fees on every deposit/withdraw by capping reinvestment at ~1% of pool value and discounting newly minted LP tokens by the fee share they confer. Both safeguards can be defeated: the reinvestment check compares raw fee token amounts rather than their price-weighted value, so after a large price move the fees can far exceed the 1% cap without triggering reinvestment, and the LP-token discount is skipped outright whenever a few wei of the secondary token are supplied alongside a deposit. An attacker can therefore flash-loan a large single-sided amount, add a token-amount dust supply to disable the discount, deposit to capture the majority of pool shares, and immediately withdraw to seize the bulk of the accumulated fee0/fee1 balances. The confirmed, mitigated finding includes a working mainnet-fork PoC showing a risk-free ~1.58 WETH profit that is multiple times the intended 1% cap.
Metric: Discarding sub-quantum oracle precision lets low-priced assets trade below their signed value
Metric's oracle consumer floors Pyth Lazer prices to eight decimals when a feed's exponent is below -8, truncating the sub-quantum remainder without folding the discarded quantization error into the spread or uncertainty band used by the anchored price provider. Because the provider constructs its protective bid/ask band around that already downward-biased midpoint, a fresh, correct and stale-free Pyth report for a low-priced asset like SHIB can still let a permissionless swapper buy the token out of the pool below its correctly signed oracle value. In the demonstrated configuration an LP funding 25,000,000,000 SHIB (worth about $102,942.50 at the correct midpoint) loses roughly $89.70 of mark-to-market principal, which clears Sherlock's Medium thresholds of both 0.01% of affected principal and $10. The protocol team acknowledged and fixed the issue in a follow-up commit.
stNXM by EaseDeFi: Missing Uniswap V3 cardinality initialization in `StNxmOracle` leads to permanent Denial of Service
The StNxmOracle contract prices stNXM from a 30-minute Uniswap V3 TWAP, but its constructor only stores the pool address and never grows the pool's observation buffer. Newly initialized Uniswap V3 pools keep a default observationCardinality of 1, which holds only the current block, so OracleLibrary.consult requests for 1800 seconds of history always revert. Every price() call therefore fails and the oracle is unusable, bricking the Morpho lending markets that depend on it for collateral valuations until an external actor manually raises the cardinality. The root cause is an initialization gap in the constructor: it must call increaseObservationCardinalityNext (e.g., 100 slots) before the oracle is used. This was a Sherlock medium finding fixed by the protocol team in commit 98c0058.
All reports in this group
- stNXM by EaseDeFi: Attacker can profit by manipulating Uniswap liquidity.Oracle manipulation$0
- Centrifuge Protocol V3.1: `SimplePriceManager.onUpdate()` lack of forward execution fee leads dependent functions to revertOracle manipulation$0
- Brevis Pico ZKVM: Malicious verifier will recover private witness values breaking zero-knowledge propertyOracle manipulation$0
- Oku Trade Order Types: Precision loss allows a mallicious user to drain amount received from ordersOracle manipulation$0
- Cap: Utilization rate multiplier will not shift if oracle is consulted frequentlyOracle manipulation$0
- Notional Exponent: Incorrect assumption that one (1) Pendle Standard Yield (SY) token is equal to one (1) Yield Token when computing the price in the oracleOracle manipulation$0
- Notional Exponent: Attacker can drain the entire suppliers on Morpho market by inflating collateral priceOracle manipulation$0
- Usual ETH0: Lack of on-chain deviation check for LST can lead to loss of assetsOracle manipulation$0
- Symmio, Staking and Vesting: USDC rewards will not be distributed if `_updateRewardsStates` is triggered too oftenOracle manipulation$0
- Yieldoor: `Strategy::checkPoolActivity()` incorrect check leads to vulnerable priceOracle manipulation$0
- Nibiru: `IOracle.queryExchangeRate` returns incorrect `blockTimeMs`Oracle manipulation$0
- Peapods: spTKNMinimalOracle `_calculateSpTknPerBase()` does not calculate correct price for podded or fraxlend pair pairedLpTKNs.Oracle manipulation$0
- NOYA: `NoyaValueOracle.getValue` returns an incorrect price when a multi-token route is usedOracle manipulation$0
- NOYA: `_getPositionTVL` of `UNIv3Connector` wrongly assumes ownership of all liquidity of the provided ticks inside `positionManager`Oracle manipulation$0
- NOYA: Value of asset token can be incorrect when usage of ETH/USD Chainlink oracle is neededOracle manipulation$0
- Peapods: `spTKNMinimalOracle.sol` counts debond fee twice, which will make the end price (spTKN per base) higher than it should beOracle manipulation$0
- Rubicon: Users might get less assets than expected upon migration due to price manipulation attacksOracle manipulation$0
- Peapods: Incorrect `minAnswer` check doesn't protect the protocol from massive price dropsOracle manipulation$0
- Plaza Finance: BondOracleAdapter can fetch price from inefficient Pool on AerodromeOracle manipulation$0
- Plaza Finance: BondOracleAdapter will cause massive loss of funds for a large number of bond tokensOracle manipulation$0
- Oku's New Order Types Contract: Incorrect Freshness Logic Validation in PythOracle breaking the entire mechanism for triggering ordersOracle manipulation$0
- MorphL2: Sequencer will be underpaid because of incorrect `commitScalar`Oracle manipulation$0
- Boost Core Incentive Protocol: Both block.prevrandao and block.timestamp are not reliably source of randonnessOracle manipulation$0
- Flayer: ````UniswapImplementation.beforeSwap()```` is vulnerable to price manipulation attackOracle manipulation$0
- ZeroLend One: `GenericLogic.sol` contract assumes all price feeds has the same decimals but is a wrong assumption that leads to an incorrect health factor math.Oracle manipulation$0
- Velar Artha PerpDEX: LPs will withdraw more value than deposited during pegged token de-peg eventsOracle manipulation$0
- BendDAO: Major insolvency risk in `LiquidationLogic::executeCrossLiquidateERC721()` due to not setting a maximum liquidation priceOracle manipulation$0
- BendDAO: `isolateRedeem()` revert in case Revert-on-zero-value-transfers tokensOracle manipulation$0
- BendDAO: PriceOracle has invalid checks on price stalenessOracle manipulation$0
- BendDAO: Updating asset collateral params can lead to liquidate borrowers arbitrarilyOracle manipulation$0
- BendDAO: No check if Arbitrum/Optimism L2 sequencer is down in Chainlink feeds `PriceOracle.sol`Oracle manipulation$0
- Sentiment V2: RedStone oracle is vulnerable because ```updatePrice``` is not called during the ```getEthValue``` function.Oracle manipulation$0
- Sentiment V2: `ChainlinkOracle` doesn't validate for minAnswer/maxAnswerOracle manipulation$0
- Sentiment V2: Red Stone Oracle Can Time TravelOracle manipulation$0
- Optimism: LPP metadata can be altered after the challenge period is over, allowing incorrect states to be provenOracle manipulation$0
- Optimism: An attacker can bypass the challenge period during LPP finalizationOracle manipulation$0
- Optimism: L2 precompile calls can be impossible to reproduce on L1Oracle manipulation$0
- Optimism: The LPP challenge period can cause malicious and freeloader claims to be uncounterable and can also cause freeloader claims to be abused to entrap honest challengersOracle manipulation$0
- Common Stableswap: stale price can be prolonged Oracle manipulation$0
- Predy: Chainlink's `latestRoundData` might return stale or incorrect resultsOracle manipulation$0
- Predy: PriceFeed does not return to the correct price for quote pairsOracle manipulation$0
- Predy: Incorrect price for negative ticks due to lack of rounding downOracle manipulation$0
- Predy: Liquidators can bypass remaining negative margin check and leave the loss to the protocolOracle manipulation$0
- Predy: Liquidity manipulation is possible when tradingOracle manipulation$0
- Notional Leveraged Vaults: Pendle PT and Vault Incentives: Incorrect valuation of vault shareOracle manipulation$0
- DittoETH: `oracleCircuitBreaker`: Not checking if price information of asset is staleOracle manipulation$0
- BakerFi: `ETHOracle.getLatestPrice` needs to convert to 18 decimalsOracle manipulation$0
- Panoptic: `_validatePositionList()` does not check for duplicate tokenIds, allowing attackers to bypass solvency checksOracle manipulation$0
- BakerFi: Multiple swap lack slippage protectionOracle manipulation$0
- Panoptic: `PanopticFactory` uses spot price when deploying new pools, resulting in liquidity manipulation when mintingOracle manipulation$0
- BakerFi: Min and maxAnswer never checked for oracle price feedOracle manipulation$0
- Munchables: Missing disapproval check in `LockManager.sol::approveUSDPrice` allows simultaneous approval and disapproval of a price proposalOracle manipulation$0
- DYAD: Design flaw and mismanagement in vault licensing leads to double counting in collateral ratios and positions collateralized entirely with kerosineOracle manipulation$0
- DYAD: Kerosene collateral is not being moved on liquidation, exposing liquidators to lossOracle manipulation$0
- DYAD: Unable to withdraw Kerosene from `vaultmanagerv2::withdraw` as it expects a `vault.oracle()` method which is missing in Kerosene vaultsOracle manipulation$0
- DYAD: Attacker can make `0` value `deposit()` calls to deny user from redeeming or withdrawing collateralOracle manipulation$0
- DYAD: Missing enough exogenous collateral check in `VaultManagerV2::liquidate` makes the liquidation revert even if (DYAD Minted `>` Non Kerosene Value)Oracle manipulation$0
- DYAD: Liquidation bonus logic is wrongOracle manipulation$0
- DYAD: User can get their Kerosene stuck because of an invalid check on withdrawOracle manipulation$0
- DYAD: Value of kerosene can be manipulated to force liquidate usersOracle manipulation$0
- Renzo: Lack of slippage and deadline during withdraw and depositOracle manipulation$0
- Renzo: Incorrect exchange rate provided to Balancer poolsOracle manipulation$0
- Renzo: `calculateTVL` may run out of gas for modest number of operators and tokens breaking deposits, withdrawals, and tradesOracle manipulation$0
- Renzo: Fixed hearbeat used for price validation is too stale for some tokensOracle manipulation$0
- Renzo: Incorrect calculation of queued withdrawals can deflate TVL and increase ezETH mint rateOracle manipulation$0
- Renzo: The amount of `xezETH` in circulation will not represent the amount of `ezETH` tokens 1:1Oracle manipulation$0
- Renzo: stETH/ETH feed being used opens up to 2 way `deposit<->withdrawal` arbitrageOracle manipulation$0
- Renzo: Withdrawals of rebasing tokens can lead to insolvency and unfair distribution of protocol reservesOracle manipulation$0
- Arrakis Valantis SOT: ArrakisMetaVaultPrivate::fund No slippage control on private vault deposit can cause unlimited loss to ownerOracle manipulation$0
- Lavarage: A borrower can borrow SOL without backing it by a collateralOracle manipulation$0
- Revert Lend: `V3Oracle` susceptible to price manipulationOracle manipulation$0
- Revert Lend: Lack of safety buffer in `_checkLoanIsHealthy` could subject users who take out the max loan into a forced liquidationOracle manipulation$0
- Revert Lend: Large decimal of `referenceToken` causes overflow at oracle price calculationOracle manipulation$0
- Revert Lend: Tokens can't be removed as a collateral without breaking liquidations and other core functionsOracle manipulation$0
- Revert Lend: Users cannot stop loss in AutoRange and AutoExitOracle manipulation$0
- Revert Lend: `_getReferencePoolPriceX96()` will show incorrect price for negative tick deltas in current implementation cause it doesn't round up for themOracle manipulation$0
- AI Arena: Can mint NFT with the desired attributes by reverting transactionOracle manipulation$0
- Wise Lending: Off-by-one bug prevents the `_compareMinMax()` from detecting Chainlink aggregators' circuit-breaking eventsOracle manipulation$0
- Wise Lending: Liquidating chaining can be achieved by liquidating token collateral with the highest `collateralFactor`Oracle manipulation$0
- Abracadabra Money: Missing Return Statement in `_getReserves` Function in `MagicLpAggregator` ContractOracle manipulation$0
- Abracadabra Money: Anyone making use of the MagicLP's TWAP to determine token prices will be exploitable.Oracle manipulation$0
- Wise Lending: Exiting a farm on mainnet assumes a peg of `1:1` when swapping stETH for ETHOracle manipulation$0
- Abracadabra Money: Pool Creation Failure Due to WETH Transfer Compatibility Issue on Some ChainsOracle manipulation$0
- Wise Lending: Liquidators can pay less than required to completely liquidate the private collateral balance of an uncollateralized positionOracle manipulation$0
- Wise Lending: The protocol allows borrowing small positions that can create bad debtOracle manipulation$0
- Wise Lending: `PendlePowerManager` is incompatible with `PendleRouterV3`Oracle manipulation$0
- Abracadabra Money: MagicLpAggregator always returns lower than correct answer, leading to arbitrage lossOracle manipulation$0
- Wise Lending: User can erase their position debt for freeOracle manipulation$0
- Wise Lending: Incorrect bad debt accounting can lead to a state where the `claimFeesBeneficial` function is permanently bricked and no new incentives can be distributed, potentially locking pending and future protocol fees in the `FeeManager` contractOracle manipulation$0
- Abracadabra Money: Oracle price can be manipulatedOracle manipulation$0
- Abracadabra Money: `MagicLpAggregator` can be incompatible with potential integrators due to incorrect `latestRoundData` functionOracle manipulation$0
- Wise Lending: Current heartbeat implementation may lead to a prolonged DoS for Chainlink OraclesOracle manipulation$0
- Abracadabra Money: MagicLpAggregator doesn't consider the dcimal of MagicLPOracle manipulation$0
- Zivoe: OCL_ZVE.sol::forwardYield relies on manipulable Uniswap V2 pool reserves leading to theft of fundsOracle manipulation$0
- Ondo Finance: `OUSGInstantManager` will allow excessive `OUSG` token minting during `USDC` depeg eventOracle manipulation$0
- Amphora Protocol: When Convex pool is shut down while collateral type is `CurveLPStakedOnConvex`, users unable to deposit that asset and protocol lose the ability to accept the asset as collateral furtherOracle manipulation$0
- Salty.IO: Adversary can prevent updating price feed addresses by creating poisonous proposals ending in `_confirm`Oracle manipulation$0
- Salty.IO: If there is only one USDS borrower, he can never be liquidatedOracle manipulation$0
- Salty.IO: Minimium Collateral Check Can Be BypassedOracle manipulation$0
- Salty.IO: Attacker Can Inflate LP Position Value To Create a Bad Debt LoanOracle manipulation$0
- Salty.IO: `_getUniswapTwapWei()` will show incorrect price for negative ticks cause it doesn't round up for negative ticksOracle manipulation$0
- Salty.IO: Incorrect calculation to check remaining ratio after reward in StableConfig.solOracle manipulation$0
- Salty.IO: Attacker can take advantage of Chainlink price not occuring within it's 60 minute heartbeat to make PriceAggregator calls failOracle manipulation$0
- Salty.IO: The use of spot price by CoreSaltyFeed can lead to price manipulation and undesired liquidationsOracle manipulation$0
- Salty.IO: formPOL lacks slippage and deadline protectionOracle manipulation$0
- Flat Money Fix Review: Attacker can steal LPs funds by using different oracle prices in the same transactionOracle manipulation$0
- HydraDX: Users can MAKE EMA-Oracle price outdated with direct transfers to StableSwapOracle manipulation$0
- Perennial V2 Update #2: ChainlinkFactory will pay non-requested versions keeper feesOracle manipulation$0
- PoolTogether: `yieldFeeBalance` wouldn't be claimed after calling `transferTokensOut()`Oracle manipulation$0
- WOOFi Swap: Pool can be drainedOracle manipulation$0
- WOOFi Swap: Price manipulation by swapping any ````baseToken```` with itselfOracle manipulation$0
- WOOFi Swap: WooFi oracle can fail to validate its price with Chainlink price feedOracle manipulation$0
- Perpetual: Two Pyth prices can be used in the same transaction to attack the LP poolsOracle manipulation$0
- Tapioca: Leverage borrowing with stale rate can atomically create bad debt with no prior positions and no investmentOracle manipulation$0
- Origami: An attacker can bypass the dynamic fees in `lovStEth` vault under certain depeg conditions, and extract value from honest depositorsOracle manipulation$0
- Smilee Finance: PositionManager will revert when trying to return back to user excess of the premium transferred from the user when minting positionOracle manipulation$0
- eBTC Protocol: `fetchPrice` can return different prices in the same transactionOracle manipulation$0
- Asymmetry Finance: Missing circuit breaker checks in `ethPerCvx()` for Chainlink's price feedOracle manipulation$0
- Asymmetry Finance: AfEth deposits could use price data from an invalid Chainlink responseOracle manipulation$0
- Flat Money: Malicious keepers can manipulate the price when executing an orderOracle manipulation$0
- Flat Money: Oracle will not failover as expected during liquidationOracle manipulation$0
- Notional Update #5: The use of spot data when discounting is subjected to manipulationOracle manipulation$0
- INIT Capital: API3 oracle timestamp can be set to future timestamp and block API3 Oracle usage to make code revert in underflowOracle manipulation$0
- Ubiquity: LibUbiquityPool::mintDollar/redeemDollar reliance on outdated TWAP oracle may be inefficient for preventing depegOracle manipulation$0
- Ubiquity: LibTWAPOracle::update Providing large liquidity will manipulate TWAP, DOSing redeem of uADsOracle manipulation$0
- NextGen: The `RandomizerVRF` and `RandomizerRNG` do not produce hash value.Oracle manipulation$0
- Open Dollar: Unable to retrieve price information with CamelotRelayer contractOracle manipulation$0
- Open Dollar: Decimal Limitation in CamelotRelayer and UniV3Relayer Contract DeploymentOracle manipulation$0
- Kelp DAO: The price of rsETH could be manipulated by the first stakerOracle manipulation$0
- Kelp DAO: Update in strategy will cause wrong issuance of sharesOracle manipulation$0
- Wildcat Protocol: Blocked accounts keep earning interest contrary to the WhitePaperOracle manipulation$0
- Tapioca DAO: Anybody can buy collateral on behalf of other users without having any allowance using the multiHopBuyCollateral()Oracle manipulation$0
- Tapioca DAO: Liquidation transactions can potentially fail for all marketsOracle manipulation$0
- Tapioca DAO: The amount of debt removed during `liquidation` may be worth more than the account's collateralOracle manipulation$0
- Tapioca DAO: User's assets can be stolen when removing them from the Singularity market through the Magnetar contractOracle manipulation$0
- Tapioca DAO: Attacker can prevent rewards from being issued to gauges for a given epoch in TapiocaOptionBrokerOracle manipulation$0
- Tapioca DAO: Incorrect liquidation reward computation causes excess liquidator rewards to be givenOracle manipulation$0
- Tapioca DAO: Magnetar contract has no approval checkingOracle manipulation$0
- Maia DAO Ecosystem: Use of `slot0` to get `sqrtPriceLimitX96` can lead to price manipulation.Oracle manipulation$0
- Maia DAO Ecosystem: Branch Strategies lose yield due to wrong implementation of time limit in `BranchPort.sol`Oracle manipulation$0
- Lybra Finance: Lack of timelock on `rigidRedemption`, enables to steal yield from other usersOracle manipulation$0
- Asymmetry Finance: `WstEth` derivative assumes a `~1=1` peg of stETH to ETHOracle manipulation$0
- Asymmetry Finance: Possible DoS on `unstake()`Oracle manipulation$0
- Asymmetry Finance: Price of sfrxEth derivative is calculated incorrectlyOracle manipulation$0
- Asymmetry Finance: Reth `poolPrice` calculation may overflowOracle manipulation$0
- Asymmetry Finance: Staking, unstaking and rebalanceToWeight can be sandwiched (Mainly rETH deposit)Oracle manipulation$0