Normally, after a treasure is claimed using a valid ZK proof, the claimed mapping is updated to prevent the same treasureHash from being reused, protecting the contract from draining attacks.
However, in TreasureHunt.sol at line 88, there is a critical typo. The claim function checks claimed[_treasureHash] instead of checking the parameter treasureHash. Because _treasureHash is an uninitialized immutable private state variable, it strictly evaluates to bytes32(0). Thus, the replay check always evaluates claimed[bytes32(0)], which is always false.
This completely bypasses the replay protection. A single legitimate user or attacker with ONE valid proof can repeatedly call claim() to systematically drain the entire contract's ETH (e.g., 100 ETH) until claimsCount >= MAX_TREASURES is hit.
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.