The joinEvent() function allows users to participate in the tournament by selecting a team to bet on. Under normal behavior, a user should only be able to join the event once, selecting a single team to support. The function should track the user's participation and prevent duplicate entries.
However, the current implementation lacks any mechanism to prevent users from calling joinEvent() multiple times. Each call to joinEvent() adds the user's address to the usersAddress[] array without checking if they already exist, updates their country selection, and increments participant counters. This allows a single user to join the event multiple times with different or the same country selections, effectively allowing them to hedge their bets by supporting multiple teams simultaneously.
The specific issue is that the function performs usersAddress.push(msg.sender) on line 263 without any duplicate check, and increments numberOfParticipants++ on line 265 even when the same user calls the function multiple times. This breaks the intended one-participation-per-user design and creates inconsistencies in participant tracking and winner share calculations.
Likelihood:
High - This vulnerability occurs whenever a user calls joinEvent() more than once. Since there is no validation preventing multiple calls, any user who has deposited funds can exploit this by simply calling the function multiple times with different countryId parameters before the eventStartDate.
High - The function accepts any valid countryId on each call, allowing users to join multiple different teams in a single transaction or across multiple transactions, as long as they occur before the event starts.
Impact:
Users can hedge their bets by joining multiple teams, breaking the intended one-bet-per-user design and creating unfair advantages
The usersAddress[] array grows with duplicate entries, causing gas inefficiencies and incorrect participant counting
The numberOfParticipants counter becomes inaccurate, showing more participants than actual unique users
Explanation of PoC:
This proof of concept demonstrates the vulnerability by showing that a single user can successfully call joinEvent() multiple times with different country selections. The test performs the following steps:
Setup: User deposits 5 ETH to participate in the tournament
First Join: User joins with country 10 (Japan) - this should be the only allowed join
Second Join: User joins again with country 20 (France) - this should fail but doesn't
Third Join: User joins a third time with country 30 - still allowed, proving the vulnerability
Explaination :
The recommended mitigation prevents users from joining the event multiple times by adding a check at the beginning of the joinEvent() function. The fix uses the existing userToCountry mapping to detect if a user has already joined - if the mapping has a non-empty value, it means the user has already participated.
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.