Users can call joinEvent() multiple times without restrictions, artificially inflating their share count and diluting rewards for other winners. This allows attackers to steal funds from legitimate winners.
Normal behavior expects users to call joinEvent() once after depositing to select their team. The function should track that a user has already joined and prevent duplicate entries.
The current implementation has no check to prevent multiple joinEvent() calls. Each call increments numberOfParticipants, adds the user address to usersAddress[] again, and accumulates totalParticipantShares repeatedly with the same user's shares.
Likelihood:
User can call joinEvent() immediately after first call, with no on-chain restrictions preventing it
The function only checks for deposit existence and valid countryId, both of which remain true on subsequent calls
Attack can be executed before event starts, with zero additional cost beyond gas
Impact:
Attacker's shares are counted multiple times in totalParticipantShares, artificially inflating the denominator
When _getWinnerShares() executes in setWinner(), attacker's shares are added multiple times to totalWinnerShares
During withdraw(), each winner's payout = (userShares * finalizedVaultAsset) / totalWinnerShares
Inflated totalWinnerShares means all winners receive proportionally less
Attacker steals value from all other winning participants
usersAddress[] array fills with duplicates, wasting gas and potentially causing DOS
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.