withdraw() is the function the owner uses to recover leftover ETH after all treasures have been claimed. Every other privileged function in the contract is gated on msg.sender == owner, but withdraw() has no such check.
Likelihood:
The condition claimsCount >= MAX_TREASURES is publicly observable; any watcher can call withdraw() the moment it becomes true.
No funds are at risk of theft (they always go to owner), so the cost to trigger this is only gas.
Impact:
The owner cannot delay the withdrawal to resolve disputes or audit the final state a third party can force it immediately.
The Withdrawn event does not record the caller, making on-chain attribution misleading for accounting tools.
Once the claimsCount >= MAX_TREASURES condition is met, any address — including an automated bot watching the mempool can call withdraw() and trigger the payout immediately. The funds always flow to owner, so there is no direct theft, but the owner loses the ability to defer the withdrawal for any operational reason (e.g., dispute resolution, final accounting).
Adding the onlyOwner modifier is a one-line change that brings withdraw() in line with every other privileged function in the contract. This ensures the owner retains sole discretion over when the final payout is executed, consistent with the stated design intent.
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.
The contest is complete and the rewards are being distributed.