DeFiLayer 1Layer 2
14,723 OP
View results
Submission Details
Severity: low
Invalid

Incorrect Oracle Updates Allow Cross-Chain Arbitrage and Liquidity Drain

Summary

The Curve scrvUSD Savings Vault relies on oracle updates to propagate accurate price and rate information across chains. If an incorrect blockhash is provided in the update_price() function and not corrected in a timely manner, the system may process invalid pricing data. Simultaneously, the update_profit_max_unlock_time() function can progress the system’s block_number even while the erroneous data persists. This may allow attackers to exploit mispriced assets in Curve’s stableswap-ng pools, leading to potential cross-chain arbitrage opportunities and liquidity drains from affected pools. Although smoothing mechanisms and APR caps offer mitigation, delayed correction of oracle data still exposes the protocol and liquidity providers to significant financial risk.

Vulnerability Details

The vulnerability stems from oracle data updates dependent on external blockhash verification, which can occasionally be incorrect or delayed as mention in the docs that;

It can be updated frequently with a mainnet blockhash that is no older than, say, 30 minutes. The minimal delay is 64 blocks to avoid any potential mainnet reorg risks.
It can __rarely__ provide an incorrect blockhash, but not an incorrect block number. Thus, a new update with a fresh block number will correct the parameters.

The Curve oracle architecture allows both update_price() and update_profit_max_unlock_time() to modify the block_number, but there is no enforced synchronization ensuring that an incorrect oracle price is corrected before progressing the system state.

update_price(): Updates scrvUSD price based on a provided blockhash and other parameters.

assert self.last_block_number <= _block_number, "Outdated"
self.last_block_number = _block_number

update_profit_max_unlock_time(): Updates the profit unlock timeline and advances block_number, even when the previous price update was erroneous.

assert self.last_block_number <= _block_number, "Outdated"
self.last_block_number = _block_number

If an incorrect blockhash leads to the propagation of an inaccurate price or rate block_number advances regardless of the incorrect data. Smoothing mechanisms and rate caps limit short-term damage but cannot prevent systematic exploitation of incorrect data.

Until the incorrect blockhash and price are corrected, the following conditions are present; Mispriced scrvUSD in stableswap-ng pools Profit unlock mechanisms operating on inaccurate rate assumptions.

Impact

  • Mispriced scrvUSD on L2 chains (e.g., Optimism, Arbitrum) leads to arbitrage opportunities. Attackers can buy undervalued scrvUSD on L2, bridge it back to Ethereum where it has higher value, and profit from the spread Conversely, if scrvUSD is overpriced, attackers can sell into Curve L2 pools, draining assets like USDC or FRAX.

  • Curve’s stableswap-ng pools rely on the oracle for price alignment. A faulty price that isn’t corrected promptly results in imbalanced pools, making them susceptible to being drained on one side.

Tools Used

Manual Review

Recommendation

Implement strict validation to prevent either update_profit_max_unlock_time() or update_price() from progressing the block_number unless the most recent oracle price update is verified as accurate.

Updates

Lead Judging Commences

0xnevi Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope
Assigned finding tags:

[invalid] finding-block-number-no-input-check

- Anything related to the output by the `BLOCK_HASH_ORACLE` is OOS per \[docs here]\(<https://github.com/CodeHawks-Contests/2025-03-curve?tab=readme-ov-file#blockhash-oracle>). - The PoC utilizes a mock `BLOCK_HASH_ORACLE`which is not representative of the one used by the protocol - Even when block hash returned is incorrect, the assumption is already explicitly made known in the docs, and the contract allows a subsequent update within the same block to update and correct prices - All state roots and proofs must be verified by the OOS `StateProofVerifier` inherited as `Verifier`, so there is no proof that manipulating block timestamp/block number/inputs can affect a price update - There seems to be a lot of confusion on the block hash check. The block hash check is a unique identifier of a block and has nothing to do with the state root. All value verifications is performed by the OOS Verifier contract as mentioned above

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.