Normal behavior: Post-hunt withdrawal of leftover funds is an organizer-controlled action, or it is documented that any party may trigger settlement.
Problem: withdraw() has no onlyOwner modifier. Once claimsCount >= MAX_TREASURES, any caller can invoke it. ETH still goes to owner, but the caller and timing are not restricted to the owner.
Likelihood:
After the tenth claim, any EOA or contract can call withdraw() on the next block or later.
Bots or third parties routinely observe contract state and call public settlement-style functions.
Impact:
Owner loses exclusive control over when post-hunt funds are swept, which matters for accounting, taxes, and coordination with off-chain hunt closure.
No direct theft to an arbitrary address here, but policy and operational expectations break.
Explanation: After ten claims, ATTACKER calls withdraw() while OWNER receives the ETH. The test proves msg.sender need not be the owner.
Supporting code — run (fixtures from circuits/scripts/build.sh):
Supporting code — test:
Explanation: Post-hunt withdrawal should be an owner-controlled administrative action. Restricting withdraw with onlyOwner preserves exclusive control over timing and accounting while keeping funds routed to owner as today.
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.