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

DAO Parameter Misconfiguration

Summary

The set_max_price_increment function allows the DAO to set max_price_increment up to 10**18 (100% per second), far exceeding the intended 0.5 bps/block safety threshold. This could disable price smoothing, making the oracle manipulable and risking pool drainage.

Vulnerability Details

The vulnerable code is in set_max_price_increment:

vyper

@external
def set_max_price_increment(_max_price_increment: uint256):
access_control._check_role(access_control.DEFAULT_ADMIN_ROLE, msg.sender)
assert 10**8 <= _max_price_increment and _max_price_increment <= 10**18
self.max_price_increment = _max_price_increment
  • Overly Permissive Range:

    • Docs suggest 0.5 bps/block (≈ 5 * 10**11 per second), but 10**18 is allowed.

    • _smoothed_price uses this to cap price jumps, so a high value negates protection.

  • DAO Control: Only mitigated by governance diligence.

PoC

Objective

Set max_price_increment to 10**18, disabling smoothing and enabling rapid price manipulation.

Prerequisites

  • Control of DEFAULT_ADMIN_ROLE in the scrvUSD oracle (e.g., DAO compromise or test setup).

  • Deployed scrvUSD oracle.

Exploit Scenario

An attacker sets max_price_increment to its maximum, allowing unchecked price jumps to manipulate pools.

Proof of Concept Steps

  1. Setup: Deploy the oracle and grant DEFAULT_ADMIN_ROLE to the attacker.

  2. Exploit Contract:

    solidity

    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.18;
    interface IScrvusdOracle {
    function set_max_price_increment(uint256 _max_price_increment) external;
    function update_price(uint256[7] calldata _parameters, uint256 _ts, uint256 _block_number) external returns (uint256);
    function price_v1() external view returns (uint256);
    }
    contract ExploitDAOMisconfig {
    IScrvusdOracle public oracle;
    constructor(address _oracle) {
    oracle = IScrvusdOracle(_oracle);
    }
    function exploit() external {
    oracle.set_max_price_increment(10**18); // Max value
    uint256[7] memory params = [1000, 500, 1000, block.timestamp + 7 days, 1000, block.timestamp - 1 days, 2000];
    oracle.update_price(params, block.timestamp, block.number); // Baseline
    params[0] = 10000; // Spike total_debt
    oracle.update_price(params, block.timestamp + 1, block.number + 1); // Huge jump
    }
    function check() external view returns (uint256) {
    return oracle.price_v1(); // Reflects massive increase
    }
    }
  3. Execution:

    • Call exploit() to set max_price_increment and spike the price.

    • check() shows a drastic price increase (e.g., 10x), bypassing smoothing.

  4. Result: Rapid price swing exploitable in pools (e.g., drain USDC side).

Outcome

Shows how DAO misconfiguration enables manipulation, violating safety guarantees.

Impact

Manipulation: A high max_price_increment allows rapid price swings, exploitable in stableswap-ng pools.

  • Pool Drainage: Attackers could drain one side of the pool by inflating/deflating prices.

  • Trust Violation: Undermines the oracle’s manipulation-resistance promise.

Tools Used

Manual Review

Recommendations

Cap max_price_increment at a safer value (e.g., 5 * 10**11 for 0.5 bps/block):

vyper

@external
def set_max_price_increment(_max_price_increment: uint256):
access_control._check_role(access_control.DEFAULT_ADMIN_ROLE, msg.sender)
assert 10**8 <= _max_price_increment and _max_price_increment <= 5 * 10**11, "Exceeds safe threshold"
self.max_price_increment = _max_price_increment
Updates

Lead Judging Commences

0xnevi Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
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.