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

The Oracle contract allows an attacker with privileged roles to freeze price updates by submitting arbitrarily high future block numbers.

Summary

This report details a high-severity vulnerability identified in the ScrvusdOracleV2.vy contract. The vulnerability allows an attacker with the PRICE_PARAMETERS_VERIFIER or UNLOCK_TIME_VERIFIER role to freeze oracle updates by submitting a transaction with a future block number. This could prevent legitimate price updates for an extended period, potentially causing significant issues for dependent protocols.

Vulnerability Details

ScrvusdOracleV2.vy#L295-L348

The vulnerability is present in both the update_price and update_profit_max_unlock_time functions:

@external
def update_price(
_parameters: uint256[ALL_PARAM_CNT], _ts: uint256, _block_number: uint256
) -> uint256:
"""
...
"""
access_control._check_role(PRICE_PARAMETERS_VERIFIER, msg.sender)
# Allowing same block updates for fixing bad blockhash provided (if possible)
assert self.last_block_number <= _block_number, "Outdated"
self.last_block_number = _block_number
...
@external
def update_profit_max_unlock_time(_profit_max_unlock_time: uint256, _block_number: uint256) -> bool:
"""
...
"""
access_control._check_role(UNLOCK_TIME_VERIFIER, msg.sender)
# Allowing same block updates for fixing bad blockhash provided (if possible)
assert self.last_block_number <= _block_number, "Outdated"
self.last_block_number = _block_number
...

The issue arises because:

  1. The code only checks that the provided _block_number is greater than or equal to the current last_block_number.

  2. There is no upper bound check to ensure the provided _block_number is not far in the future.

  3. Once updated, last_block_number becomes the new baseline for all future updates.

While the code includes a comment about "Allowing same block updates for fixing bad blockhash provided", this doesn't address the vulnerability of setting arbitrarily high future block numbers.

Impact

The impact of this vulnerability is severe:

  1. Oracle Freeze: An attacker with the appropriate role could submit a transaction with a block number far in the future, effectively freezing the oracle's ability to update prices or unlock times.

  2. Stale Data: During the freeze period, the oracle would continue to serve stale price data, which could lead to incorrect pricing in dependent protocols.

  3. Financial Losses: DeFi protocols relying on this oracle could experience significant financial losses due to incorrect pricing, especially during periods of high market volatility.

  4. Extended Downtime: The freeze could last until the blockchain reaches the attacker's specified block number, which could be days, weeks, or even months.

  5. Difficult Recovery: Once the attack is executed, there is no simple way to recover without protocol governance intervention or contract upgrades.

Tools Used

  • Manual code review

  • Understanding of Vyper 0.4.0 language features

  • Analysis of contract business logic

Recommendations

To mitigate this vulnerability, consider implementing the following changes:

  1. Add Upper Bound Check: Modify the block number validation to include an upper bound check:

# Recommended fix
assert self.last_block_number <= _block_number <= block.number + MAX_FUTURE_BLOCKS, "Invalid block number"
self.last_block_number = _block_number

Where MAX_FUTURE_BLOCKS is a reasonable constant (e.g., 100 blocks) that allows for some block number flexibility without enabling the attack.

  1. Use Current Block Number: Consider using the current block.number directly instead of allowing callers to specify it:

# Alternative fix
self.last_block_number = block.number
  1. Emergency Recovery Mechanism: Implement an emergency function that allows privileged roles to reset last_block_number in case of an attack:

@external
def emergency_reset_block_number():
access_control._check_role(ADMIN_ROLE, msg.sender)
self.last_block_number = block.number
  1. Monitoring: Implement off-chain monitoring to detect unusual jumps in last_block_number that might indicate an attack.

By implementing these recommendations, the contract would be protected against this high-severity vulnerability while maintaining its intended functionality.

Updates

Lead Judging Commences

0xnevi Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

[invalid] finding-centralization-risk

- Per [codehawks documentation](https://docs.codehawks.com/hawks-auditors/how-to-determine-a-finding-validity#findings-that-may-be-invalid) - Parameter change is executed via the Dao per docs > Also, it is worth noting that the oracle is controlled by a DAO and its parameters can be changed by a vote.

Support

FAQs

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