Normal behavior: Each treasure is uniquely identified by its hash and can be claimed only once. The contract should prevent duplicate claims and preserve reward invariants across claims.
The issue is that the contract uses a single immutable _treasureHash for all treasures instead of mapping each valid treasure hash. This causes any valid proof for _treasureHash to permit repeated claims against the same stored key, breaking the uniqueness invariant.
Likelihood:
Occurs whenever multiple valid treasures exist but only one is recognized in state.
Appears during normal claim() flows when proofs correspond to distinct treasure secrets but match the same _treasureHash.
Impact:
Attackers may forge repeated claims using different valid proofs but identical public hash binding.
Allows extractor to drain ETH rewards for all MAX_TREASURES or more.
Track each valid treasure hash separately using the mapping and use that key to prevent duplicates.
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.