The claim function is intended to prevent users from claiming the same treasure multiple times by checking a claimed mapping. Under normal behavior, a successful claim should mark the specific treasure hash as "true" in the mapping and revert any future attempts using that same hash.
However, a critical logic error exists where the duplicate check and the storage update use different variables. The contract checks _treasureHash (an incorrect or undefined identifier) but updates the mapping using treasureHash (the actual function parameter).Describe the normal behavior in one or more sentences
Likelihood:
Reason 1 This vulnerability is present in the core claim logic and is triggered every time a user attempts to claim a reward.
Reason 2 The duplicate check always evaluates to false because the slot being checked is never the slot being written to.
Impact:
Impact 1 An attacker can completely drain the contract's ETH balance with only one legitimate treasure discovery.
Impact 2 A single valid ZK proof can be reused infinitely by a single participant.
In `claim()`, the guard uses `claimed[_treasureHash]`, where `_treasureHash` is an immutable state variable that is never initialized to the caller-supplied treasure identifier, while the contract later marks `claimed[treasureHash] = true` using the function argument instead. As a result, the duplicate-claim check and the state update are performed against different keys, which means a previously claimed treasure is not actually blocked from being claimed again with the same valid proof and `treasureHash`. This breaks a core invariant of the protocol described in the README, namely, that each treasure can only be redeemed once, and allows one valid treasure/proof pair to be reused to drain rewards repeatedly until either the `MAX_TREASURES` cap or the contract balance is exhausted.
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.