hats-finance / SeeR-PM-0x899bc13919880db76edf4ccd72bdfa5dfa666fb7

1 stars 0 forks source link

Unbounded Market Creation Leading to Gas Exhaustion and Potential Denial of Service #102

Open hats-bug-reporter[bot] opened 3 weeks ago

hats-bug-reporter[bot] commented 3 weeks ago

Github username: @DevPelz Twitter username: Pelz_Dev Submission hash (on-chain): 0x04eff2ab0e3258632487e501ca6602da6a9bc37711e52be608728e21c66de8c2 Severity: high

Description:

Description

The createMarket function allows users to create multiple markets without incurring fees. It is called internally by various functions such as createMultiCategoricalMarket and createCategoricalMarket, which are external functions open to user interaction. Each new market created is pushed to an array (markets.push(address(instance))) without limits. This creates an opportunity for malicious users to flood the contract by creating numerous markets at little to no cost, causing the array to grow. As the array grows, gas costs for subsequent transactions that iterate or interact with the markets array increase, leading to out-of-gas errors and potential denial of service for the protocol.

Functions affected include but are not limited to:

Attack Scenario

A malicious user can exploit this vulnerability by continuously creating fake markets through the external functions createMultiCategoricalMarket and createCategoricalMarket. Since there are no fees or restrictions on the number of markets created, the attacker can easily populate the markets array with fake addresses. As a result:

  1. The growing size of the markets array increases gas costs for interactions with it.
  2. Eventually, legitimate user transactions may fail due to out-of-gas errors.
  3. The protocol could become unusable, leading to a denial of service for other users and overall disruption of platform functionality.

Attachments

  1. Proof of Concept (PoC) File (PoC omitted as per request)

  2. Revised Code File (Optional) To mitigate this vulnerability, we suggest the following adjustments:

    • Replace the markets array with a mapping to store addresses more efficiently.
    • Introduce a counter to track the number of markets created.
    • Optionally, implement a fee or rate-limiting mechanism to discourage abuse.

Revised Code

// Proposed fix to replace unbounded array with a mapping and market count.
mapping(uint256 => address) public marketsMapping;
uint256 public marketsCount;

// Update the market creation logic
function createMarket(
    CreateMarketParams memory params,
    string memory marketName,
    InternalMarketConfig memory config
) internal returns (address) {
    (Market.ConditionalTokensParams memory conditionalTokensParams, Market.RealityParams memory realityParams) =
        createNewMarketParams(params, config);

    Market instance = Market(market.clone());

    instance.initialize(
        marketName,
        params.outcomes,
        params.lowerBound,
        params.upperBound,
        conditionalTokensParams,
        realityParams,
        realityProxy
    );

    emit NewMarket(
        address(instance),
        marketName,
        params.parentMarket,
        conditionalTokensParams.conditionId,
        conditionalTokensParams.questionId,
        realityParams.questionsIds
    );

    // Replace the array push with a mapping assignment and increment the count
    marketsMapping[marketsCount] = address(instance);
    marketsCount++;

    return address(instance);
}
greenlucid commented 3 weeks ago

Can you provide an example of a function that iterates through all markets and becomes impossible to be called as a result?

clesaege commented 3 weeks ago

Yeah, there is no functions which have a complexity related to the number of markets.