claim() breaks duplicate protection (replay issue)The TreasureHunt:claim function is supposed to stop users from claiming the same treasure twice by checking the claimed mapping.
But instead of checking the function input treasureHash, it incorrectly checks an uninitialized state variable _treasureHash.
Since _treasureHash is never set in the constructor, it is always zero, so the check always looks at the wrong mapping key.
Because of this mistake, the contract does not properly track whether a specific treasure has already been claimed
Likelihood:
. This issue will occur every single time the claim() function is executed.
Because _treasureHash is never initialized, it always remains bytes32(0), meaning the contract consistently checks the same incorrect mapping key regardless of the input provided by users.
As a result, duplicate claims are not blocked in any scenario, and the issue is not dependent on any specific attacker behavior, timing, or external condition.
Impact:
Same treasure can be claimed multiple times
ZK proof can be reused again and again
Reward funds can be drained multiple times
Core rule of “one claim per treasure” is broken
Replace the incorrect state variable _treasureHash with the function parameter treasureHash in the mapping check so each treasure is tracked properly.
Additionally, remove the unused _treasureHash state variable from the contract entirely to prevent confusion and reduce the risk of similar logical errors in future implementations.
This issue is marked High severity because it directly breaks a core security invariant of the protocol and allows repeated valid claims, leading to potential loss of funds without any special conditions or privileged access.
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.