Normal Behavior: Administrative functions that handle the sweeping of remaining or unclaimed funds are strictly designed to be executed by the contract owner. This allows the protocol administrators to manage their treasury, calculate taxes, or move funds to a cold wallet on their own specific schedule.
Specific Issue: The withdraw function lacks the onlyOwner modifier. The function only checks if the hunt is over (claimsCount >= MAX_TREASURES). Once this condition is met, any external user, bot, or attacker can call the function. While the funds are hardcoded to be sent to the owner address (preventing theft), this permissionless execution removes the owner's control over the exact timing of the withdrawal, which can disrupt off-chain accounting systems or trigger unwanted tax events for the protocol.
Likelihood:
Any user or MEV bot can execute this function immediately after the final treasure is claimed.
Impact:
No direct loss of funds, as the ETH is securely routed to the owner address.
Protocol griefing through forced operational timing. The owner loses control over when the transaction occurs.
The following Foundry test demonstrates how an unauthorized user can force the withdrawal:
The test simulates a state where all 10 treasures have been successfully claimed.
A random user (attackerAddress) calls the withdraw() function.
Because there is no msg.sender == owner check, the transaction succeeds.
The remaining contract balance is forcefully pushed to the owner without their consent.
Explanation of the fix: Implementing the existing onlyOwner modifier ensures that the EVM checks msg.sender == owner before executing the logic. This restores full control to the protocol administrators regarding when the remaining treasury is swept.
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.