Skip to content

Latest commit

 

History

History
210 lines (158 loc) · 6.52 KB

017.md

File metadata and controls

210 lines (158 loc) · 6.52 KB

Flaky Merlot Parrot

High

Lack of Validation for Slippage and Critical Parameters Will Cause Execution Failures and Unfavorable Trades for Users

Summary

The absence of input validation for critical parameters, including slippage values (takeProfitSlippage, stopSlippage) and other user-defined parameters (amountIn, feeBips), will cause execution failures and unfavorable trades for users as attackers or misconfigurations can exploit these unchecked inputs. This vulnerability is propagated through multiple functions in Brackets.sol, creating a chain of risks that impact the overall reliability and security of the contract.

Root Cause

  1. Unvalidated Slippage Parameters:
  1. Unbounded Input Parameters:

Critical parameters such as amountIn, feeBips, takeProfitSlippage, and stopSlippage are not validated in the following functions:

  • fillStopLimitOrder
  • createOrder
  • _initializeOrder

Internal pre-conditions

  1. Misconfigured Inputs: A user or attacker sets extreme values for slippage, amountIn, or feeBips.

  2. No Validation During Order Creation: Functions like createOrder and _initializeOrder do not validate input ranges for these critical parameters.

External pre-conditions

  1. Market Fluctuations:
  • Volatile market conditions exacerbate the impact of misconfigured slippage, leading to failed trades or unfavorable execution.

Attack Path

Step-by-Step Issue Breakdown I- Function: checkUpkeep() Role: Determines whether an order is ready for execution and calculates the required slippage.

Vulnerable Code:

slippage: takeProfit ? order.takeProfitSlippage : order.stopSlippage,

No validation for order.takeProfitSlippage or order.stopSlippage allows extreme values, causing:

  • Unfavorable execution rates.
  • Unexpected trade behavior.
  1. An attacker sets takeProfitSlippage to 10,000 (100%) during order creation.
  2. During checkUpkeep, the contract calculates slippage using the unchecked value:
slippage: takeProfit ? order.takeProfitSlippage : order.stopSlippage,
  1. The order executes at an extremely unfavorable rate.

II- Function: performUpkeep() Role: Executes the orders flagged by checkUpkeep().

Vulnerable Code:

takeProfit ? bips = order.takeProfitSlippage : bips = order.stopSlippage;

No validation for slippage values results in incorrect bips (basis points) calculation, leading to:

  • Failed swaps due to out-of-range slippage.
  • Potential financial loss.
  1. An attacker sets stopSlippage = 0 during order creation.
  2. During performUpkeep, the swap fails as the slippage is insufficient for any price fluctuation:
bips = order.stopSlippage; // Zero slippage

III- Functions: createOrder and _initializeOrder Role: These functions are responsible for initializing and validating new orders.

Vulnerable Code:

require(
    stopSlippage <= 10000 &&
    takeProfitSlippage <= 10000 &&
    feeBips <= 10000,
    "BIPS > 10k"
);
  • Although this code checks for excessively high values (e.g., BIPS > 10k), it does not:
    • Enforce a reasonable minimum slippage (e.g., non-zero values).
    • Validate amountIn for proper ranges (e.g., greater than zero).
  • Missing checks for negative or zero values allows orders to be initialized with invalid parameters.
  1. An attacker initializes an order with amountIn = 0.
  2. The system processes this order, but no tokens are available for execution, causing unexpected behavior.

Here’s how the vulnerabilities propagate through the contract:

checkUpkeep:

//checkUpkeep
function checkUpkeep(
    bytes calldata
) external view override returns (bool upkeepNeeded, bytes memory performData) {
    for (uint96 i = 0; i < pendingOrderIds.length; i++) {
        Order memory order = orders[pendingOrderIds[i]];
        (
            bool inRange,
            bool takeProfit,
            uint256 exchangeRate
        ) = checkInRange(order);
        if (inRange) {
            return (
                true,
                abi.encode(
                    MasterUpkeepData({
                        slippage: takeProfit
                            ? order.takeProfitSlippage
                            : order.stopSlippage,
                        // Other data...
                    })
                )
            );
        }
    }
}

performUpkeep:

//performUpkeep:
function performUpkeep(
    bytes calldata performData
) external override nonReentrant {
    MasterUpkeepData memory data = abi.decode(performData, (MasterUpkeepData));
    Order memory order = orders[pendingOrderIds[data.pendingOrderIdx]];

    // Deduce bips
    uint16 bips;
    takeProfit ? bips = order.takeProfitSlippage : bips = order.stopSlippage;

    // Other logic...
}

createOrder and _initializeOrder:

//createOrder and _initializeOrder:
function _initializeOrder(
    uint256 amountIn,
    uint16 feeBips,
    uint16 takeProfitSlippage,
    uint16 stopSlippage
) internal {
    require(amountIn > 0, "Amount must be greater than zero");
    require(feeBips <= 10000, "Fee too high");
    require(takeProfitSlippage <= 500, "Take profit slippage too high");
    require(stopSlippage <= 500, "Stop slippage too high");
    // Other logic...
}

Impact

Financial Loss: Users may suffer significant losses due to unfavorable slippage rates.

Trade Failures: Orders fail when slippage is set too low or when input parameters (e.g., amountIn) are invalid.

System Disruption: Invalid inputs can lead to logical errors and failed executions across the platform.

PoC

No response

Mitigation

  1. Input Validation:

Enforce strict validation for all critical parameters:

require(amountIn > 0, "Amount must be greater than zero");
require(feeBips <= MAX_FEE_BIPS, "Fee too high");
require(takeProfitSlippage > MIN_SLIPPAGE && takeProfitSlippage <= MAX_SLIPPAGE, "Invalid take profit slippage");
require(stopSlippage > MIN_SLIPPAGE && stopSlippage <= MAX_SLIPPAGE, "Invalid stop loss slippage");

Define Constants:

  1. Set reasonable bounds for slippage and fees:
uint16 constant MAX_SLIPPAGE = 500; // 5%
uint16 constant MIN_SLIPPAGE = 10;  // 0.1%
uint16 constant MAX_FEE_BIPS = 1000; // 10%
Refactor Logic:
  1. Use consistent validation logic across all functions to prevent propagation of invalid inputs.