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

Hardcoded storage slots may lead to incorrect price calculations and oracle manipulation

Summary

The Verifier contracts (V1 and V2) rely on hardcoded storage slots to extract parameters from the scrvUSD contract. If the storage layout of the scrvUSD contract changes (e.g., due to upgrades or compiler optimizations), the Verifiers will read incorrect data, leading to invalid price calculations and potential oracle manipulation.

Vulnerability Details

The Verifier contracts rely on hardcoded storage slots to extract parameters from the scrvUSD contract:

// ScrvusdVerifierV1.sol
uint256[PROOF_CNT] internal PARAM_SLOTS = [
uint256(0), // filler for account proof
uint256(21), // total_debt
uint256(22), // total_idle
uint256(20), // totalSupply
uint256(38), // full_profit_unlock_date
uint256(39), // profit_unlocking_rate
uint256(40), // last_profit_update
uint256(keccak256(abi.encode(18, SCRVUSD))) // balanceOf(self)
];
// ScrvusdVerifierV2.sol
uint256 internal PERIOD_SLOT = 37; // profit_max_unlock_time

Solidity doesn't guarantee storage slot stability across contract upgrades or compiler versions

  • ScrvusdVerifierV1.sol defines PARAM_SLOTS as fixed storage slots (e.g., total_debt at slot 21, total_idle at slot 22).

  • ScrvusdVerifierV2.sol assumes profit_max_unlock_time is stored at slot 37.

  • If the scrvUSD contract’s storage layout changes (e.g., new variables are added, reordering occurs), these slots will point to unrelated data. e.g., if total_debt moves to a different slot, the Verifier will read wrong values, causing the oracle to compute an incorrect price.

POC

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract ScrvusdOld {
uint256 public total_debt; // Slot 21
uint256 public total_idle; // Slot 22
uint256 public profit_max_unlock_time; // Slot 37
}
// Introduce a new variable, and shift all storage slots down by 1 slot
contract ScrvusdNew {
uint256 public new_variable; // Newly added at slot 21
uint256 public total_debt; // Now at slot 22
uint256 public total_idle; // Now at slot 23
uint256 public profit_max_unlock_time; // Now at slot 38
}
contract MalfunctioningVerifier {
address public scrvUSD;
constructor(address _scrvUSD) {
scrvUSD = _scrvUSD;
}
function getTotalDebt() external view returns (uint256) {
uint256 slot = 21; // Hardcoded slot assumption
uint256 value;
assembly {
value := sload(slot)
}
return value;
}
}


Impact

  • The oracle ends up being fed incorrect parameters, leading to manipulated scrvUSD prices.
    A malicious actor could exploit this to drain liquidity pools (e.g., arbitrage at incorrect rates) or destabilize the system.

  • Example: If total_supply is read as 0 due to slot misalignment, the oracle’s _raw_price will attempt division by zero, causing transaction reverts and denial-of-service.

Tools Used

Manual Review

Solc-select

Recommendations

  • Allow for dynamic configuration of storage slots via governance or admin functions instead of hardcoding them.

  • Implement a mechanism to validate the storage layout (e.g., checks against known hashes of the scrvUSD contract’s state variables).

Updates

Lead Judging Commences

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

[invalid] finding-upgradeable-verifier-contracts

Invalid, - srCRVUSD is a minimal proxy, meaning it can never by upgraded, see [here](https://www.cyfrin.io/blog/upgradeable-proxy-smart-contract-pattern#:~:text=Minimal%20proxies%20are%20distinct%20from,provide%20upgrade%20or%20authorization%20functionality.) and [here](https://www.rareskills.io/post/eip-1167-minimal-proxy-standard-with-initialization-clone-pattern) for more info. - Even if srcrvUSD is migrated in the future via a new minimal proxy contract deployment (which is highly unlikely), the verifier contracts can be migrated along with it via revoking the access-control within the `ScrvusdOracleV2.vy` and then granting access to a new oracle. This is also not within the scope of this contest.

Support

FAQs

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