Describe the normal behavior in one or more sentences
Explain the specific issue or problem in one or more sentences
The TreasureHunt contract declares bytes32 private immutable _treasureHash but never assigns it in the constructor. It permanently equals bytes32(0).
The double-spend guard in claim() reads claimed[_treasureHash] — this always checks the zero slot, which is never set to true. Meanwhile _markClaimed(treasureHash) correctly writes the parameter hash — but the guard never reads that slot. The protection is a permanent no-op.
Description
Normal behavior: after a treasure is claimed, claimed[treasureHash] is set to true, and subsequent calls with the same hash should revert with AlreadyClaimed.
Actual behavior: the guard checks claimed[bytes32(0)] which is always false, so the same proof can be replayed indefinitely until claimsCount reaches 10.
Likelihood:
Reason 1 // Describe WHEN this will occur (avoid using "if" statements)
Reason 2
Impact:
Impact 1
Impact 2
Likelihood:
Any holder of a single valid ZK proof can exploit this immediately with no special tools
The attack requires only calling claim() 10 times in sequence — no flashloan, no special contract needed
Impact:
A single treasure secret drains the entire 100 ETH contract balance (10 claims x 10 ETH)
All 10 claim slots are consumed, permanently locking out legitimate treasure finders
The hunt organizer loses all deposited funds
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.