If a player is registered multiple times with different rewards, the player only receives the minimum of these rewards, with the remaining amount being redistributed. This results in a loss for the affected player while benefiting other players and the contest manager. Furthermore, if such a situation occurs, a player cannot claim their reward multiple times. Attempting to call claimCut
twice by the same player results in a Pot__RewardNotFound()
revert.
The vulnerability primarily lies in the following line of code:
Here, the claimCut
function lacks a check for address duplication when assigning rewards to a player. As a result, in cases of duplicated addresses, the player receives only the minimum reward assigned to them.
Additionally, consider the following line of code:
https://github.com/Cyfrin/2024-08-MyCut/blob/946231db0fe717039429a11706717be568d03b54/src/Pot.sol#L43
In this line, the reward corresponding to a player is set to zero in the playersToRewards
map. Consequently, if a player with a duplicated address has already claimed their reward once, any remaining rewards under their name are set to zero in the map. If they attempt to call the claimCut
function again, the transaction reverts, as seen in the following if
statement:
To demonstrate this vulnerability, I modified the players
and rewards
arrays as follows:
Technically, player1
should receive 300+200=500
ETH if claimed within 90 days, while player2
should receive 100 ETH.
However, to test the actual behavior, I created the following testDuplicacy
function:
In this test, I attempted to call the claimCut
function twice for player1
, but it resulted in a revert:
Next, I modified the testDuplicacy()
function:
This resulted in the following output:
The test demonstrates that player1
is able to claim only once and therefore receives the minimum of the two rewards associated with it's address 200 ETH, while player2
receives their 100 ETH. The remaining 300 ETH is distributed among the players , ContestManager
and the contest
contract as shown:-
Loss of ETH for player1
Gain in ETH for ContestManager and other players
Significant amount of ETH remains in the contest contract which neither goes to the players nor to the Contest Manager.
Manual Analysis
Implement a duplicate address check in the claimCut()
function to prevent this vulnerability.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.