The briVault::cancelParticipation function lets anyone cancel their participation after they have joined the event. Such functionality should definitely be there, in case the user feels like opting out of the event.
However, the function only refunds assets and burns shares, and does not remove the user from:
userAddress array
userSharesToCountry[user][countryId]
etc..
Because of this, when setWinner() later calls _getWinnerShares(), the user is still counted as a participant and still contributes ghost shares to totalWinnerShares, even though:
They no longer have shares
They no longer have staked assets
They are no longer participating
This means the user who cancelled reduces everyone else’s withdrawal payout because the denominator becomes inflated due to stale ghost shares, directly stealing value from the real winners.
Likelihood: High
Any participant can do this intentionally before the event starts.
No special timing, no fee, no privileged access needed.
Impact: High/Medium
Cancelling users steal a portion of the reward pool from real winners.
Can prevent winners from withdrawing entirely (DoS) if the vault becomes insolvent.
System fairness breaks completely.
For this, two tests have been created; it's advisable to run them both.
First test, test_HonestScenario, shows how things might look in a normal case:
2nd test, test_UserStillPartOfEventEvenAfterCancellation, showcases the vulnerability part:
Run both tests using:
Logs:
cancelParticipation must fully revert the user's tournament state:
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.