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

Arbitrary Timestamp Acceptance in Update Functions

1. Summary

  • Severity: Medium

  • Category: Input Validation

  • Impact: Potential price manipulation through timestamp specification

  • Likelihood: Medium (requires compromised trusted role)


2. Affected Code

@external
def update_price(
_parameters: uint256[ALL_PARAM_CNT], _ts: uint256, _block_number: uint256
) -> uint256:
access_control._check_role(PRICE_PARAMETERS_VERIFIER, msg.sender)
assert self.last_block_number <= _block_number, "Outdated"
self.last_block_number = _block_number
# ...
self.price_params_ts = _ts
# ...
  • Contract: ScrvusdOracleV2.vy

  • Function: update_price

  • Line(s) Affected: ~325-343


3. Vulnerability Details

Root Cause

The update_price function validates that _block_number is not outdated but fails to perform any validation on the provided timestamp _ts. This allows a verifier to specify arbitrary timestamps that can significantly affect price calculations.

Attack Scenario

  1. A compromised or malicious actor with the PRICE_PARAMETERS_VERIFIER role calls update_price

  2. They provide a timestamp _ts that is significantly different from the actual block timestamp

  3. This manipulation influences all price calculations, particularly price_v1 which relies directly on the stored timestamp

  4. The manipulated prices create arbitrage opportunities at the expense of liquidity providers


4. Proof of Concept (PoC)

def demonstrate_timestamp_manipulation():
# Assume we have a ScrvusdOracleV2 contract deployed
# And the attacker has PRICE_PARAMETERS_VERIFIER role
current_time = chain.time()
# Simulate a compromised verifier setting future timestamp
with boa.env.prank(verifier):
oracle.update_price(
valid_parameters,
current_time + 30 days, # Setting a timestamp 30 days in the future
current_block_number
)
# Check the price calculation - it will be accelerated
future_expected_price = oracle.price_v1()
print(f"Manipulated future price: {future_expected_price}")
# This will create arbitrage opportunities against the pool

5. Recommended Fix

Proposed Solution

@external
def update_price(
_parameters: uint256[ALL_PARAM_CNT], _ts: uint256, _block_number: uint256
) -> uint256:
access_control._check_role(PRICE_PARAMETERS_VERIFIER, msg.sender)
assert self.last_block_number <= _block_number, "Outdated"
# Add timestamp validation
max_timestamp_deviation = 1 hours
assert _ts >= block.timestamp - max_timestamp_deviation, "Timestamp too old"
assert _ts <= block.timestamp + max_timestamp_deviation, "Timestamp too future"
self.last_block_number = _block_number
# ...rest of the function...

Alternative Mitigation Strategies

  • Use block.timestamp directly instead of allowing custom timestamps

  • Implement a time-weighted average price (TWAP) mechanism to reduce the impact of timestamp manipulation

  • Add additional validation requiring multiple verifiers to confirm the timestamp


6. Severity Justification

  • Impact: Medium to High - Manipulated timestamps can lead to incorrect price calculations, creating arbitrage opportunities and potential pool imbalances

  • Likelihood: Medium - The vulnerability requires a compromised or malicious actor with the PRICE_PARAMETERS_VERIFIER role, which is a trusted position in the system

Updates

Lead Judging Commences

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

[invalid] finding-missing-proof-content-validation

- See [here]([https://github.com/CodeHawks-Contests/2025-03-curve?tab=readme-ov-file#blockhash-oracle)](https://github.com/CodeHawks-Contests/2025-03-curve?tab=readme-ov-file#blockhash-oracle) on how it is used to verify storage variable - All state roots and proofs must be verified by the OOS `StateProofVerifier` inherited as `Verifier` (where the price values and params are extracted), so there is no proof that manipulating timestamp/inputs can affect a price update - It is assumed that the OOS prover will provide accurate data and the OOS verifier will verify the prices/max unlock time to be within an appropriate bound/values - There is a account existance check in L96 of `ScrvusdVerifierV1.sol`, in which the params for price updates are extracted from

Support

FAQs

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