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

Inconsistent Timestamp Sources Leading to `ScrvusdOracleV2:: price_params_ts` Parameter Reversion, Potentially Causing Price Calculation Errors

Summary

The verifyScrvusdByStateRoot and verifyScrvusdByBlockHash functions in ScrvusdVerifierV1 contract have inconsistent timestamp sources passed to the ScrvusdOracleV2::update_price function. In the verifyScrvusdByStateRoot function, the timestamp passed to ScrvusdOracleV2::update_price is the block timestamp from the submitted block header, while verifyScrvusdByStateRoot uses the last_profit_update from the scrvUSD contract state. Combined with the lack of sequential validation on the provided timestamp in ScrvusdOracleV2::update_price, this creates the risk of overwriting the ScrvusdOracleV2::price_params_ts parameter with an older timestamp, which could lead to incorrect price calculations.

Vulnerability Details

In the ScrvusdVerifierV1 contract, the verifyScrvusdByBlockHash and verifyScrvusdByStateRoot functions are responsible for updating the price parameters in the ScrvusdOracleV2 contract. However, these functions use different sources for the timestamp passed to the update_price function, leading to potential inconsistencies:

  1. verifyScrvusdByBlockHash function: Uses the block timestamp from the submitted block header as the timestamp for the update_price function. (https://github.com/CodeHawks-Contests/2025-03-curve/blob/198820f0c30d5080f75073243677ff716429dbfd/contracts/scrvusd/verifiers/ScrvusdVerifierV1.sol#L66)

  2. verifyScrvusdByStateRoot function: Reads the last_profit_update from the storage slot of the scrvUSD contract as the time reference, which only reflects the last profit update time within the contract. (https://github.com/CodeHawks-Contests/2025-03-curve/blob/198820f0c30d5080f75073243677ff716429dbfd/contracts/scrvusd/verifiers/ScrvusdVerifierV1.sol#L79)

The block timestamp serves as an objective time reference from the blockchain network, while last_profit_update relies on the business logic trigger time within the contract.

Due to the lack of validation in the ScrvusdOracleV2::update_price function to ensure that the input_ _ts is greater than or equal to the current price_params_ts, there is a timestamp reversion risk. Furthermore, since the verifyScrvusdByBlockHash and verifyScrvusdByStateRoot functions lack access control restrictions, anyone can call these functions, increasing the likelihood of this vulnerability being exploited.

Example:

  1. Legitimate Update Trigger

    • The prover calls verifyScrvusdByBlockHash, passing the block header containing T1 (the latest block timestamp).

    • The _ts passed to the update_price function is T1, and price_params_ts is updated to T1, recording the accurate time reference.

  2. Outdated Parameter Injection

    • The prover or attacker calls verifyScrvusdByStateRoot, passing _ts as last_profit_update (the scrvUSD contract's last_profit_update has not been updated ,still T0, where T0 < T1), which is T0.

  3. Timestamp Reversion

    • Since update_price lacks sequence verification for _ts, price_params_ts is reverted to T0.

When ScrvusdOracleV2:: price_params_ts is reverted to an earlier timestamp, the following price calculation issues arise:

  1. Inaccurate Yield Period Calculation: The ScrvusdOracleV2:: _obtain_price_params function relies on the correct timestamp to calculate the number of yield periods and asset growth. A timestamp reversion leads to incorrect period calculations, which in turn affects the calculation of _total_assets and _total_supply.

  2. Price Smoothing Mechanism Failure: The ScrvusdOracleV2:: _smoothed_price function depends on the timestamp difference to calculate the maximum allowed price variation. A timestamp reversion disrupts this mechanism, potentially causing price fluctuations beyond the expected range.

  3. Price Prediction Bias: The ScrvusdOracleV2:: _price_v0, ScrvusdOracleV2:: _price_v1, and ScrvusdOracleV2:: _price_v2 functions all depend on the correct timestamp sequence. A timestamp reversion leads to inconsistent price values being output by these functions.

Impact

If the ScrvusdOracleV2:: price_params_ts value is overwritten by an older timestamp, it could result in erroneous price calculations, which could ultimately affect the price feed provided to the system.

Tools Used

Manual

Recommendations

Add the following in ScrvusdOracleV2::update_price:

assert _ts >= self.price_params_ts, "Timestamp reversion".
Updates

Lead Judging Commences

0xnevi Lead Judge 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-last_profit_update-used-instead-timestamp

- Sponsor Comments - State root oracles usually do not provide block.timestamp, so it's simply not available. That is why last_profit_update is intended. - In `update_price`, this value must be a future block, meaning this update is a state checked and allowed by the OOS verifier contracts. The impact is also increasingly limited given price is smoothen and any updates via the block hash `verifyScrvusdByBlockHash` can also update the prices appropriately, meaning the price will likely stay within safe arbitrage range aligning with protocol logic

Support

FAQs

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