The intended claim flow is: verify a proof for `(treasureHash, recipient)`, ensure the referenced treasure has not been claimed yet, then transfer exactly one fixed reward for that treasure.
The implementation checks `claimed[_treasureHash]` instead of `claimed[treasureHash]`. Since `_treasureHash` is never initialized in the constructor, the replay-prevention gate does not track the treasure being claimed. As a result, the same valid proof and the same `treasureHash` can be reused to receive multiple payouts.
Likelihood: HIGH
Any user holding one valid proof can resubmit the same `(proof, treasureHash, recipient)` tuple multiple times because the duplicate-claim gate never checks the actual `treasureHash` being consumed.
The repository's own fixtures already contain a valid proof, and the PoC shows the issue is exploitable without special setup or malformed inputs.
Impact: HIGH
A single discovered treasure can be paid out more than once, breaking the protocol's core one-treasure/one-reward invariant.
Repeated submissions can drain the ETH reward pool that was meant to cover all treasures.
Paste this code and add to test file, then run it
To fix this just simple, we can remove the _treasureHash that imutable variable since we never use it, and change the check in claim() function with treasureHash from function params instead _treasureHash
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.