The call tracking mechanism has an edge cases where it decrements counters without properly incrementing them first, or vice versa. This is happening in error paths or exceptional conditions. The verifier is meant to safely handle external calls to the oracle and blockhash oracle contracts, but this negative call depth suggests the contract is prematurely returning from functions without properly maintaining its call stack discipline.
The root of this issue is in how the verifier contracts manage their control flow during external calls. Looking at ScrvusdVerifierV1.sol
, we can see it makes external calls to the blockhash oracle and the scrvUSD oracle: verifyScrvusdByBlockHash
The scrvUSD system likely assumed that Solidity's execution model would naturally maintain call depth integrity. After all, when you call a function, you should always return from it exactly once, right?
But here's the cognitive gap, the interaction between the verifier contracts and external oracles creates unexpected execution paths, especially around error conditions. As described in Curve's documentation, the system relies on blockhash oracles that "can rarely provide an incorrect blockhash" which introduces edge cases in the execution flow.
This is reminiscent of the infamous "reentrancy before checks" pattern, but more subtle because it involves the system's internal state tracking rather than direct value flows.
This vulnerability strikes at the core of what makes Curve's cross-chain solution work. The entire premise of scrvUSD markets on secondary chains relies on accurate price information flowing from Ethereum. When the verification layer breaks down, all downstream systems built on this truth particularly the stableswap-ng pools that use this price data are potentially compromised.
Imagine what happens when scrvUSD traverses chains. On Ethereum, it's a sophisticated ERC4626 vault token earning yield on crvUSD. When bridged to another chain, it becomes a regular ERC20 that depends entirely on the oracle to represent its true value. The verification system is the only protection ensuring that this representation stays honest.
The way this system fails is subtle but severe. When the verifier makes external calls to the blockhash oracle and later to the scrvUSD oracle, it's supposed to maintain proper tracking of these calls. But somewhere in this between contracts, the tracking gets broken, allowing call depth to reach negative values:
When call depth tracking breaks, the system can no longer guarantee that verification functions execute their logic in the expected sequence. It opens the door to verification steps being skipped or incorrectly processed, potentially allowing invalid state proofs to be accepted as valid.
StableSwap-NG pools relying on this oracle could experience significant price manipulation
According to Curve's documentation, "If not precise enough, this can lead to MEV in the liquidity pool, at a loss for the liquidity providers"
In extreme cases, "the pool being drained from one side" becomes possible
The impact of this vulnerability is directly tied to Curve's stated goals. Their documentation emphasizes that price data must be "safe (non-manipulable) and precise (no losses due to approximation)." This vulnerability threatens both guarantees.
The documentation explicitly warns that if the oracle is "not precise enough, this can lead to MEV in the liquidity pool, at a loss for the liquidity providers." And in worse cases, it can lead to "the pool being drained from one side" exactly what this vulnerability might enable.
Manual Review
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.