The joinEvent() function maintains a usersAddress[] array to track all participants. Under normal behavior, each user should appear only once in this array, ensuring efficient iteration and accurate participant counting.
However, the joinEvent() function on line 263 performs usersAddress.push(msg.sender) without any duplicate check, allowing the same address to be added multiple times when users call joinEvent() multiple times. When _getWinnerShares() iterates through this array on lines 193-195, it processes duplicate entries unnecessarily, wasting gas. Additionally, numberOfParticipants is incremented on line 265 for each join, even if the user already exists, causing the counter to show more participants than actual unique users.
Likelihood:
This vulnerability occurs when users call joinEvent() multiple times, as the function adds msg.sender to usersAddress[] on every call without checking if the address already exists in the array
The bug manifests during every iteration of _getWinnerShares() and whenever numberOfParticipants is accessed, as duplicate entries cause unnecessary processing and incorrect counts
Impact:
Gas costs increase unnecessarily during winner share calculation as _getWinnerShares() iterates through duplicate entries, processing the same user multiple times
The numberOfParticipants counter becomes inaccurate, showing more participants than actual unique users
The array grows unbounded with duplicates, causing increasing gas costs over time
Explanation of PoC:
This proof of concept demonstrates how duplicate entries in the usersAddress[] array cause gas waste and incorrect participant counting. The test shows that when a user joins multiple times, they appear multiple times in the array, causing numberOfParticipants to be incorrect and wasting gas during _getWinnerShares() iterations.
Test Results:
✅ Same user appears multiple times in usersAddress[] array
✅ numberOfParticipants shows incorrect count
✅ Gas costs increase with duplicate entries
Explanation:
The recommended mitigation prevents duplicate entries by checking if a user has already joined before adding them to the array. This ensures each user appears only once, preventing gas waste and incorrect participant counting.
The _getWinnerShares() function is intended to iterate through all users and sum their shares for the winning country, returning the total.
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.