The oracle fails to enforce maximum age for block headers, allowing intentional use of outdated price data that breaks cross-chain price convergence and creates arbitrage opportunities.
From ScrvusdOracleV2::update_price()
:
The oracle only verifies that each new block number is greater than or equal to the previously used block number. Similarly in the update_profit_max_unlock_time
function:
As seen, the only check in the oracle during update of prices or max unlock time is that passed block is not older than the previous updated block in the oracle, however this easily allows for stale prices to be used in the destination chain, since if no updats happen for a day a prover can pass in a price for 12 hours ago and this would be accepted as a price on the destination chain where as this is a stale price.
Now, the README also hints that LayerZero could be used temporarily, for blockhash feeds with a "minimal delay is 64 blocks to avoid any potential mainnet reorg risks," but there is no actual on-chain enforcement of maximum age for block headers. This creates a serious vulnerability where stale data is accepted and used to update prices.
The layerzero integration aside, that is to say, if no updates happen on the destination chain for an extended period (e.g., a day or more), a prover can submit valid proof for a block that's 12+ hours old.
Since scrvUSD price generally increases over time (due to yield accrual), using old data will significantly undervalue the token on the destination chain, which breaks the convergence of prices accross destination chain and mainnet which is core to this protocol.
Arbitrageurs can then exploit this price divergence between chains and the magnitude of this attack increases with time - the longer between updates, the greater the potential divergence between real and reported prices.
The cross-chain nature of this protocol makes this particularly dangerous, as price synchronization relies entirely on timely proofs from Ethereum. The current implementation allows for arbitrarily old blocks to be used as long as they're newer than the last update.
Manual Review
Implement a maximum age check of the destination chain's block.timestamp
against the timestamp from the verified block headers in both oracle update functions, this can then be explicitly required to not be older than 1
hour.
I believe this to be at best informational severity as - The moment sequencer is up again, the price updates that retrieve storage values from mainnet will be pushed. To note, price updates are retrieved from storage proofs are retrieved from Ethereum scrvUSD contract, so the concept of the next updated price being outdated is not possible, given mainnet does not utilize sequencers. - There are no problems with small lags if used in liquidity pools due to fees. Fees generate spread within which price can be lagged. - All price updates are subjected to smoothing, and as you can see from the historical price movements as seen [here](https://coinmarketcap.com/currencies/savings-crvusd/), there is never a large discrepancy in prices (absolute terms), and even more unlikely given sequencer downtimes will unlikely be long. This small price changes can be safely arbitrage aligning with [protocol design](https://github.com/CodeHawks-Contests/2025-03-curve?tab=readme-ov-file#parameters) , along with the above mentioned fees - Combined with the above, the max price increments can be temporarily increased to more effectively match the most updated price.
I believe this to be at best informational severity as - The moment sequencer is up again, the price updates that retrieve storage values from mainnet will be pushed. To note, price updates are retrieved from storage proofs are retrieved from Ethereum scrvUSD contract, so the concept of the next updated price being outdated is not possible, given mainnet does not utilize sequencers. - There are no problems with small lags if used in liquidity pools due to fees. Fees generate spread within which price can be lagged. - All price updates are subjected to smoothing, and as you can see from the historical price movements as seen [here](https://coinmarketcap.com/currencies/savings-crvusd/), there is never a large discrepancy in prices (absolute terms), and even more unlikely given sequencer downtimes will unlikely be long. This small price changes can be safely arbitrage aligning with [protocol design](https://github.com/CodeHawks-Contests/2025-03-curve?tab=readme-ov-file#parameters) , along with the above mentioned fees - Combined with the above, the max price increments can be temporarily increased to more effectively match the most updated price.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.