The BriVaultTest::joinEvent() function allows a user to call it multiple times without restriction. When BriVaultTest::_getWinnerShares() iterates over usersAddress, the attacker's shares are counted multiple times, inflating the denominator and diluting payouts for honest winners.
Normal behavior: Users deposit tokens into the vault and receive vault shares proportional to their deposit. Each user may call BriVaultTest::joinEvent() to register for a country. After the event ends, the owner sets the winning country via BriVaultTest::setWinner(). All users who selected the winning country share the finalized prize pool proportionally to their vault shares.
Issue: The BriVaultTest::joinEvent() function allows a user to call it multiple times after a single deposit. Each call appends msg.sender to the usersAddress array and updates userSharesToCountry[msg.sender][countryId] with their current vault shares. When BriVaultTest::_getWinnerShares() calculates the total winning shares, it iterates over usersAddress, causing the attacker's shares to be counted multiple times, once per entry in the array. This inflates totalWinnerShares, reducing the payout for honest participants who joined only once.
Likelihood: High
Any user who has deposited atleast once can call BriVaultTest::joinEvent() repeatedly before eventStartDate
No checks preventing duplicate entries in usersAddress
Impact: Medium
Honest winners receive significantly reduced payouts.
Economic fairness of the prize distribution is broken.
Add the following two test functions to BriVaultTest.t.sol. They simulate:
Normal flow: three users deposit, join once, and withdraw fairly.
Attack flow: the same setup, but user3 (malicious) joins the event multiple times.
Run both with forge test, and you’ll notice in the attack case, the honest user’s reward drops a alot
Add deduplication in BriVaultTest::_getWinnerShares() using a mapping to ensure each user’s shares are counted only once, even if they appear multiple times inusersAddress
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.