The incomplete state cleanup in BriVault.sol::cancelParticipation() will cause a loss of winnings for legitimate winners as an attacker will deposit, join, and cancel to get a full refund while leaving ghost share data that inflates totalWinnerShares, reducing all winners' payouts with zero cost to the attacker.**
In BriVault.sol:275-289, the cancelParticipation() function only partially cleans up user state:
Missing cleanup:
usersAddress[] still contains user's address
userToCountry[user] still has team selection
userSharesToCountry[user][countryId] still has old share count
numberOfParticipants not decremented
totalParticipantShares not reduced
This creates "ghost shares" because _getWinnerShares() (lines 191-198) iterates through the usersAddress[] array:
Even though the user has:
Zero actual shares (balanceOf(user) == 0)
Received full refund
No stake in the outcome
Their old userSharesToCountry[] values are still counted in totalWinnerShares, inflating the denominator and reducing everyone's payouts.
Likelihood:
Owner needs to call setCountry() to initialize teams array
Attacker needs to have deposited at least minimumAmount + participationFee worth of assets
Attacker needs to call joinEvent() before calling cancelParticipation()
Event must not have started yet (block.timestamp < eventStartDate)
Impact:
Legitimate winners suffer an approximate loss proportional to the ghost share inflation, while the attacker loses only the participation fee (1.5% × deposit × iterations).
Attacker deposits, joins event, then cancels to get full refund. However, cancelParticipation() doesn't clean up joinEvent state:
usersAddress[] still contains attacker
userSharesToCountry[] still has old share values
When _getWinnerShares() loops through usersAddress[], it counts ghost shares, inflating totalWinnerShares and reducing all legitimate winners' payouts.
Clean up all state when user cancels participation:
CancelParticipation burns shares but leaves the address inside usersAddress and keeps userSharesToCountry populated.
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.