Open hats-bug-reporter[bot] opened 6 months ago
@luzzif The issue being described here is not valid since if two bundles are provided for the same campaign id, the second bundle would just overwrite the first one in the for loop (see here). This means two roots for a campaign id cannot exist at the same time, thus invalidating what this issue is describing.
Additionally, the underlying assumption this issue makes is the updater incorrectly updating the bundles, which is a centralization risk and out of scope as per the out-of-scope section on the Hats competition page here.
I actually decided to put the medium label here because this issue made me want to add a check regarding the double Merkle root update. While it's not an issue per-se, the backend should never create a function call with duplicate same-campaign updates, so it might make sense to add a check in that sense in the smart contract and that's why I wanted to reward the issue. Maybe it could be downgraded to a low in case.
Although the likelihood of this issue is low, the impact is high so it makes sense to rate it as Medium.
@luzzif I believe this should be a low since it is just a sanity check in place.
@sonny2k The impact cannot be high at all since not only does it rely on the updater making a mistake (which is a centralization risk as per the rules) but the issue you have described is not possible (read my first comment above).
@luzzif
i think the issue is related to centralization risk and at best should be considered low.
Yeah you guys are right, lowering this to a low
Yeah you guys are right, lowering this to a low
@luzzif SER, low, not invalid.
Oh sorry, my bad. Put the low tag back. I also addressed this here: https://github.com/metrom-xyz/contracts/commit/06da107479d3de27a9c9baab405826929af9d8fa
Oh sorry, my bad. Put the low tag back. I also addressed this here: metrom-xyz@06da107
@luzzif
i think this isn't a great way to prevent a double root update. The better way is as follows; this way, the past root will not be updated as well.
DistributeRewardsBundle calldata _bundle = _bundles[_i];
if (_bundle.root == bytes32(0)) revert InvalidRoot();
if (_bundle.data == bytes32(0)) revert InvalidData();
- for (uint256 _j = _i + 1; _j < _bundles.length; _j++) {
- if (_bundles[_i].campaignId == _bundles[_j].campaignId) revert DuplicatedDistribution();
- }
Campaign storage campaign = _getExistingCampaign(_bundle.campaignId);
+ if (campaign.root != bytes32(0)) revert InvalidData();
campaign.root = _bundle.root;
campaign.data = _bundle.data;
Oh sorry, my bad. Put the low tag back. I also addressed this here: metrom-xyz@06da107
@luzzif
i think this isn't a great way to prevent a double root update. The better way is as follows; this way, the past root will not be updated as well.
DistributeRewardsBundle calldata _bundle = _bundles[_i]; if (_bundle.root == bytes32(0)) revert InvalidRoot(); if (_bundle.data == bytes32(0)) revert InvalidData(); - for (uint256 _j = _i + 1; _j < _bundles.length; _j++) { - if (_bundles[_i].campaignId == _bundles[_j].campaignId) revert DuplicatedDistribution(); - } Campaign storage campaign = _getExistingCampaign(_bundle.campaignId); + if (campaign.root != bytes32(0)) revert InvalidData(); campaign.root = _bundle.root; campaign.data = _bundle.data;
This is wrong as a campaign will have multiple root updates in its lifetime as rewards are assigned by the backend, claims updated and in turn also the derived Merkle tree/root. What this fixes is multiple updates to the same campaign in the same transaction.
@luzzif sorry, my bad.
Github username: @sonny2k Twitter username: -- Submission hash (on-chain): 0xfbcbe4889614551e63f2f91b05ab1ad63262d8341abe84ef1103ad7e1c2b1ae6 Severity: medium
Description: Description\ In distributeRewards, there is no check if
_bundles
array argument has duplicate campaignIds. Therefore, if the updater provides duplicate entries for campaignIds, users from other campaigns may have the chance to claim rewards on the duplicate campaignId which was mistakenly put in by the updater.Attack Scenario
Attachments
distributeRewards
function should include the validation that check for duplicate campaignId