withdraw() is intended to be an owner-controlled function, but it has no msg.sender or onlyOwner check.
As a result, anyone can trigger the post-hunt withdrawal once claimsCount >= MAX_TREASURES.
Likelihood:
This happens deterministically after claimsCount reaches MAX_TREASURES
Any address can call withdraw() and force the remaining funds to be sent to the owner.
Impact:
Funds are still sent to owner, so this does not allow direct theft.
However, it violates the documented access-control model and allows arbitrary users to trigger an owner-only administrative action before the owner chooses to do so.
The PoC deploys and funds TreasureHunt, then advances the contract to the post-hunt state where claimsCount == MAX_TREASURES. Once that condition is met, an arbitrary attacker address calls withdraw() successfully. The ETH is sent to owner, but the unauthorized caller is able to execute an administrative function that the README describes as owner-controlled.
Restrict withdraw() to the owner by adding an explicit check.
The `withdraw()` function is intended as an owner-only post-hunt recovery function, but the implementation does not actually enforce any ownership check before transferring the full remaining balance to owner. The function only requires that `claimsCount >= MAX_TREASURES` and that the contract balance is nonzero, after which it sends all ETH to the stored owner address regardless of who called the function. Therefore, the access control on the function itself is incomplete because any external account can trigger the withdrawal path once the hunt is considered over.
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.