hats-finance / Metrom-0xfdfc6d4ac5807d7460da20a3a1c0c84ef2b9c5a2

Smart contracts for the Metrom project.
GNU General Public License v3.0
0 stars 0 forks source link

Unrestricted Updates to Campaign Merkle Roots Pose Significant Risks in Reward Distribution Integrity #27

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

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

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

Description: Description:
The distributeRewards function within a smart contract framework allows an authorized updater to set and update the Merkle root (root) and associated data (data) for campaign reward distributions. This function is crucial as it defines the basis for validating reward claims through Merkle proofs, ensuring that rewards are distributed according to the predefined and immutable conditions of a campaign.

However, the current implementation permits the updater to change the Merkle root of a campaign an unlimited number of times without any checks on the frequency, necessity, or impact of such changes. This flexibility, while ostensibly providing operational fluidity, introduces significant vulnerabilities in terms of data consistency, trust, and security of the funds involved in these campaigns.

The primary concern arises from the ability to alter the Merkle root at any point, which can invalidate previously valid proofs, disrupt the ongoing reward claims process, and potentially facilitate fraudulent activities if the updater role is compromised.

    function distributeRewards(DistributeRewardsBundle[] calldata _bundles) external override {
        if (msg.sender != updater) revert Forbidden();

        for (uint256 _i; _i < _bundles.length; _i++) {
            DistributeRewardsBundle calldata _bundle = _bundles[_i];
            if (_bundle.root == bytes32(0)) revert InvalidRoot();
            if (_bundle.data == bytes32(0)) revert InvalidData();
            Campaign storage campaign = _getExistingCampaign(_bundle.campaignId);
            campaign.root = _bundle.root;
            campaign.data = _bundle.data;
            emit DistributeReward(_bundle.campaignId, _bundle.root, _bundle.data);
        }
    }

Attack Scenario:
The vulnerability of unrestricted updates to the campaign Merkle root can lead to significant inconsistencies and disruptions from an operational perspective, compromising the integrity of the reward distribution process.

  1. Data Inconsistency: Frequent changes to the Merkle root can severely disrupt the consistency of global data within the smart contract. Each update to the root potentially alters the entire reward distribution landscape for the campaign.

  2. Unintended Consequences: Since the Merkle root directly affects which transactions are considered valid, changes can unintentionally affect the outcome of pending transactions. For example, a user who initiates a reward claim just before an unexpected root update might find their transaction failing because the proof no longer matches the new root. This affects the user’s ability to claim rewards.

Attachments:

Proof of Concept (PoC):

  1. Revised Code File (Optional)
luzzif commented 3 months ago

The centralization of the solution is intended and also the "power" we gave to the updater, so I think this issue is out of scope, while it's true that in some (rare) cases the updater might frontrun some reward claims by the users.