Normal behavior: Each country should have a unique identifier and verification should be based on immutable indices. Names are metadata and should not allow multiple different indices to be treated as the same winner.
Issue: The contract allows duplicate country names via setCountry. The guarded withdraw() checks string equality (userToCountry vs winner), while totalWinnerShares is computed using the winner’s index (winnerCountryId). If two different indices share the same name, users who picked the non-winner index but with the same name can pass the string check and withdraw, while the denominator (totalWinnerShares) only includes shares for the true winner index. This causes overpayment and drains the vault.
Likelihood: Low
Requires owner to set duplicates.
Still unguarded today and easy to misconfigure.
Impact: High
Users from the non-winner index with the same name can withdraw, causing overpayment and exhausting the vault.
Legitimate winners may fail to claim due to insufficient remaining assets; funds can be locked for later claimants.
Description:
Owner sets countries with duplicate names at indices 7 and 8.
Users join both indices 7 and 8; owner sets winner to index 7.
Both groups pass the string-equality check and withdraw, but totalWinnerShares only counted index 7, causing the vault to underflow for later winners.
Enforce unique country names on setCountry to prevent configuration mistakes.
Or better, prefer index-based verification for payout (do not rely on string equality). Use the snapshot of winning shares per user and winner index.
Index-based payout (avoid strings):
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.