selectWinner() and withdrawFees() Lack Access Control — Anyone Can Trigger Premature Round TerminationPuppyRaffle.selectWinner() and PuppyRaffle.withdrawFees() are both declared external without any access modifier (onlyOwner, modifier, require(msg.sender == ...)) to restrict who may call them. While selectWinner() has a time-based check (block.timestamp >= raffleStartTime + raffleDuration) and withdrawFees() has a balance check, neither restricts who can act as the caller.
The lack of access control on selectWinner() allows any EOA or contract to forcibly end a raffle the moment the time condition is satisfied, regardless of whether the protocol operator intended to continue the round. An attacker with knowledge of the raffle's timing can strategically end rounds at moments that maximize their probability of winning (e.g., having just entered as the dominant player). withdrawFees() similarly allows anyone to initiate fee extraction, potentially in combination with griefing strategies.
Likelihood: High
No barriers exist beyond time elapsed. Any participant can trigger this the moment the raffle duration expires.
Bots and MEV searchers routinely monitor protocols for permissionless termination opportunities.
Impact: High
An attacker can end a round exactly when their own player count dominates the array, maximizing their win probability under the weak randomness scheme (compounding with D02).
Prevents the protocol from accumulating a larger player pool before selecting a winner, reducing prize attractiveness.
Severity: High
An attacker monitors the blockchain for the moment block.timestamp >= raffleStartTime + raffleDuration. They call selectWinner() at a block where their own simulated output (see D02 — Weak Randomness) gives them the winning index.
Expected outcome: The attacker terminates the raffle at the most strategically advantageous time, combining with the weak randomness finding to select the round they are most likely to win.
Add onlyOwner to selectWinner() if owner-driven termination is intended, or emit an event and require a designated "operator" address:
If a permissionless termination model is desired (e.g., anyone can trigger after the window), document this explicitly in the protocol design and combine with verifiably random winner selection (Chainlink VRF) to prevent attacker timing advantage.
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.