The rarity calculation in selectWinner (L166-168) uses even fewer entropy sources than the winner selection:
Only msg.sender and block.difficulty are used -- block.timestamp is excluded. Since block.difficulty is deterministic before block finalization and msg.sender is chosen by the caller, the rarity outcome is fully predictable.
An attacker can search off-chain for an address where both the winner index and the rarity hash produce desired outcomes (e.g., legendary rarity). Because the rarity hash uses fewer inputs, this search is computationally inexpensive.
The attacker computes keccak256(candidate, block.difficulty) % 100 for multiple candidate addresses off-chain.
The attacker selects an address that produces rarity > 95 (legendary tier).
The attacker also brute-forces the msg.sender to ensure winnerIndex points to the desired player index.
The attacker calls selectWinner from the crafted address, simultaneously guaranteeing a win and a legendary NFT.
Short term: Combine the winner and rarity finding into a single recommendation: use a verifiable random function oracle for both operations.
Long term: Use Chainlink VRF or equivalent for all randomness needs. A single VRF callback can derive both the winner index and rarity from one verifiable random seed.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.