41291 sc insight winner selection vulnerability in yeetback contract allows multiple reward for the same lucky winner
#41291 [SC-Insight] Winner Selection Vulnerability in Yeetback Contract Allows Multiple Reward for the Same Lucky Winner
Submitted on Mar 13th 2025 at 12:16:19 UTC by @perseverance for Audit Comp | Yeet
Report ID: #41291
Report Type: Smart Contract
Report severity: Insight
Target: https://github.com/immunefi-team/audit-comp-yeet/blob/main/src/Yeetback.sol
Impacts:
Theft of unclaimed yield
Theft of unclaimed royalties
Description
Description
Brief/Intro
The Yeetback contract implements a winner selection mechanism where 10 winners are chosen from participants in each round to receive equal portions of the pot. However, due to a flaw in the winner selection algorithm, the same participant can be selected multiple times, allowing them to claim multiple rewards.
The vulnerability
Vulnerability Details
In the draftWinners
function of the Yeetback contract, winners are selected using the following logic:
https://github.com/immunefi-team/audit-comp-yeet/blob/main/src/Yeetback.sol#L79-L88
for (uint256 i; i < nrOfWinners; i++) {
uint256 randomDataNumber = uint256(keccak256(abi.encodePacked(randomNumber, i)));
uint256 winningYeetIndex = randomDataNumber % nrOfYeets; // index of the winning yeet
address winnerAddress = yeetsInRound[round][winningYeetIndex];
// Update amountToWinners and amountOfWins
amountOfWins[round][winnerAddress] += 1;
emit YeetbackWinner(round, winnerAddress, winnings, winningYeetIndex);
}
The contract selects 10 winners regardless of the number of participants (nrOfYeets
). Each duplicate selection increases the winner's amountOfWins
count, allowing them to claim multiple portions of the reward pot.
The duplicate is not expected by the game theory and users as the document of Yeet stated: 20% of the prize pool is distributed via verifiably random lottery to 10 participating addresses . Reference: https://docs.yeetit.xyz/yeet/yeet-game/mechanics
The vulnerability exists in some scenarios:
Scenario 1:
If the
nrOfYeets
is less than 10, the modulo operation (randomDataNumber % nrOfYeets
) will inevitably produce duplicate indices.
Probably this scenarios is not high as the number of participants in the game usually higher than 10. But still this can happen.
In scenario 2 : If
nrOfYeets
is greateer than 10, that scenario is more likely to happenThere is no check to prevent the same address from being selected multiple times, so there is probability that the winningYeetIndex is duplicated multiple times. The smaller the nrOfYeets, the higher the probability of duplicates.
Impacts
About the severity assessment
This is a High severity issue because:
It directly affects the economic fairness of the protocol
It can lead to unfair distribution of reward when the number of participants is small
The impact is more severe in early rounds or when participation is low
The duplicate is not expected by the game theory and users as the document of Yeet stated: 20% of the prize pool is distributed via verifiably random lottery to 10 participating addresses . Reference: https://docs.yeetit.xyz/yeet/yeet-game/mechanics
Bug Severity: High
I map the impact to the closest listed impact as this is related to unfair distribution of reward, lucky winner
Theft of unclaimed royalties
Theft of unclaimed yield
Recommendation
Take both scenarios in the algorithm
Implement the algorithm to avoid duplicates to avoid rewarding the same address multiple times.
Proof of Concept
Proof of Concept
Scenario 1: Small Number of Participants (nrOfYeets < 10)
Alice, Bob, and Charlie participate by yeet() in round 1. Suppose the nrOfYeets is 3 participants. The contract adds them to
yeetsInRound[1]
arrayAfter the Round1 ends and cooldown period, a user call "restart()" in Yeet.sol to start Round 2. The contract calls
addYeetback()
with 100 BERA as the pot valueThe
draftWinners()
function is called back fromentropyCallback()
to select 10 winnersDue to modulo operation with only 3 participants:
randomDataNumber % 3
will only produce values 0, 1, or 2Some addresses must be selected multiple times to reach 10 winners
Alice is selected 4 times, Bob 3 times, and Charlie 3 times
When claiming rewards:
Alice claims 4/10 of the pot (40 BERA)
Bob claims 3/10 of the pot (30 BERA)
Charlie claims 3/10 of the pot (30 BERA)
This results in unfair distribution where Alice receives more.
Scenario 2: Large Number of Participants (nrOfYeets > 10)
100 participants join Round 2 of Yeet
After the Round2 ends and cooldown period, a user call "restart()" in Yeet.sol to start Round 3. The contract calls
addYeetback()
with 100 BERA as the pot valueThe
draftWinners()
function is called back fromentropyCallback()
to select 10 winnersDue to the random modulo operation with 100 participants:
randomDataNumber % 100
can produce any value from 0 to 99There is a probability that the same index is selected multiple times
By chance, index 42 is selected twice:
First selection:
randomDataNumber1 % 100 = 42
Second selection:
randomDataNumber2 % 100 = 42
The participant at index 42:
Gets their
amountOfWins
increased twiceCan claim 2/10 of the pot (20 BERA) instead of 1/10 (10 BERA)
This creates an unfair advantage for the lucky participant who was selected multiple times
In both scenarios, the core issue is the lack of check for duplicate selections, allowing participants to receive multiple portions of the reward pot. The impact is more severe in Scenario 1 where duplicates are guaranteed, while Scenario 2 shows how the vulnerability can still affect fair distribution even with many participants.
Was this helpful?