hats-finance / SeeR-PM-0x899bc13919880db76edf4ccd72bdfa5dfa666fb7

1 stars 0 forks source link

Resolve can be spoofed because the code failed to validate the outcome content #2

Open hats-bug-reporter[bot] opened 2 hours ago

hats-bug-reporter[bot] commented 2 hours ago

Github username: -- Twitter username: -- Submission hash (on-chain): 0xe432ebda613a088596684faab1f2aa9b25b82823bf302d17e4252e6603e55bbc Severity: high

Description: Description\

When the market is created,

the code initialize the market with the following parameter:

   function initialize(
        string memory _marketName,
        string[] memory _outcomes,
        uint256 _lowerBound,
        uint256 _upperBound,
        ConditionalTokensParams memory _conditionalTokensParams,
        RealityParams memory _realityParams,
        RealityProxy _realityProxy
    ) external {
        require(!initialized, "Already initialized.");

        marketName = _marketName;
        outcomes = _outcomes;
        lowerBound = _lowerBound;
        upperBound = _upperBound;
        conditionalTokensParams = _conditionalTokensParams;
        realityParams = _realityParams;
        realityProxy = _realityProxy;

        initialized = true;
    }

However, when resolve the market in RealityProxy,

    function resolve(Market market) external {
        bytes32[] memory questionsIds = market.questionsIds();
        uint256 numOutcomes = market.numOutcomes();
        uint256 templateId = market.templateId();
        uint256 low = market.lowerBound();
        uint256 high = market.upperBound();

        // questionId must be a hash of all the values used to resolve a market, this way if an attacker tries to resolve a fake market by changing some value its questionId will not match the id of a valid market.
        bytes32 questionId = keccak256(abi.encode(questionsIds, numOutcomes, templateId, low, high));

        if (templateId == REALITY_SINGLE_SELECT_TEMPLATE) {
            resolveCategoricalMarket(questionId, questionsIds, numOutcomes);
            return;
        }

        if (templateId == REALITY_MULTI_SELECT_TEMPLATE) {
            resolveMultiCategoricalMarket(questionId, questionsIds, numOutcomes);
            return;
        }

        if (questionsIds.length > 1) {
            resolveMultiScalarMarket(questionId, questionsIds, numOutcomes);
            return;
        }

        resolveScalarMarket(questionId, questionsIds, low, high);
    }

the code only hash the number of outcome, but not the outcome content, this is a issue

and allow malicous user to create a market and resolve the market incorrectly.

  1. user A create a prediction market A, saying 1 + 1 = ?, option A: 2, option B: 3
  2. user B create a prediction market B, saying 1 + 1 = ?, option A: 4, option B: 5

In this case, user B can resolve market A because the code cannot tell if the out come is different,

the code only know that both number of out come is the same (2), the question id and template id and low and high are the same.

Attack Scenario\ Describe how the vulnerability can be exploited.

Attachments

  1. Proof of Concept (PoC) File

  2. Revised Code File (Optional)

clesaege commented 2 hours ago
user A create a prediction market A, saying 1 + 1 = ?, option A: 2, option B: 3
user B create a prediction market B, saying 1 + 1 = ?, option A: 4, option B: 5

This is not the case, if you have different options, the question will be different (keep in mind a reality question contains the potential answers), therefore the questionsIds will be different, therefore the questionId will be different.