The _getWinnerShares() function calculates the total shares held by all winners by iterating through the usersAddress[] array and summing up shares for users who bet on the winning country. Under normal behavior, each user should appear only once in the array, and their shares should be counted exactly once, resulting in an accurate totalWinnerShares value that is used to calculate proportional payouts for winners.
However, due to the Multiple Join Event Exploit, the usersAddress[] array can contain duplicate entries for the same user. When _getWinnerShares() iterates through this array on lines 193-195, it counts the same user's shares multiple times without any deduplication logic. This inflates the totalWinnerShares value, which is then used as the denominator in the payout calculation formula: assetToWithdraw = (shares * vaultAsset) / totalWinnerShares. Since the denominator is inflated, winners receive less than their fair share of the prize pool.
Likelihood:
This vulnerability occurs when setWinner() is called and the usersAddress[] array contains duplicate entries from users who exploited the Multiple Join Event vulnerability, as there is no deduplication logic in _getWinnerShares() to prevent counting the same user's shares multiple times
The bug manifests during the winner share calculation phase when _getWinnerShares() iterates through all entries in usersAddress[] without checking whether a user has already been processed, causing duplicate entries to inflate totalWinnerShares
Impact:
Winners receive less than their fair share of the prize pool because totalWinnerShares is inflated, making the denominator larger in the payout calculation formula
The financial impact scales with the number of duplicate entries, causing more significant underpayment to winners as more duplicates exist
Explanation of PoC:
This proof of concept demonstrates the vulnerability by showing how duplicate entries in the usersAddress[] array cause totalWinnerShares to be inflated, resulting in incorrect payout calculations. The test performs the following steps:
Setup: Two users deposit funds and join the event with the same winning country
Exploit: One user exploits the Multiple Join bug by joining multiple times
Winner Set: Owner sets the winner, triggering _getWinnerShares() calculation
Verification: The test verifies that totalWinnerShares is inflated due to duplicate counting
Payout Calculation: Shows that winners receive less than they should due to the inflated denominator
The test calculates the expected payout (if shares were counted correctly) versus the actual payout (with inflated totalWinnerShares) to demonstrate the financial impact.
Explanation:
The recommended mitigation fixes the _getWinnerShares() function to prevent duplicate counting by using a mapping to track which users have already been processed. This ensures each user's shares are counted exactly once, regardless of how many times they appear in the usersAddress[] array.
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.