PuppyRaffle::selectWinner allows manipulation of NFT rarityThe rarity of the minted NFT is determined using a hash of msg.sender and block.difficulty. Since both values are known or predictable, the caller of selectWinner can manipulate which rarity tier the NFT falls into -- guaranteeing a legendary puppy NFT instead of a common one.
Likelihood:
The rarity RNG uses only two predictable inputs: msg.sender (chosen by the caller) and block.difficulty (publicly known)
An attacker can precompute the rarity result for multiple sender addresses and select the one that yields a legendary NFT
Impact:
Legendary NFTs (meant to be 5% probability) can be minted on demand, destroying the intended rarity distribution
The value of legitimately rare NFTs is undermined
Four players enter the raffle normally and we advance time past the raffle duration.
The attacker iterates over a range of candidate addresses (address(1000) through address(2000)), computing the rarity formula keccak256(abi.encodePacked(candidate, block.difficulty)) % 100 for each one.
Since block.difficulty is publicly known, the attacker can do this computation entirely off-chain. They stop as soon as they find an address that produces a rarity value > 95 (the legendary range).
The test asserts that such an address is found and that its computed rarity indeed falls in the legendary tier.
In practice, the attacker would deploy a contract at a favorable address using CREATE2 (which allows deterministic address generation), or simply call selectWinner from a pre-computed EOA. Since only ~5% of addresses yield legendary, the attacker only needs to try ~20 addresses on average to find one.
Use the same Chainlink VRF randomness source for rarity as recommended for winner selection. Request an additional random word for rarity:
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.