The claim() function follows a C-I-E-I pattern instead of the correct C-E-I pattern. The external call to verifier.verify() happens before claimsCount and claimed are updated. This means if a malicious or compromised verifier re-enters claim() during verification, the state has not yet been updated and all checks pass again. The nonReentrant modifier currently prevents this, but it is load-bearing for two independent reasons simultaneously — reentrancy protection AND replay protection (due to the broken claimed check in L-1). Removing or bypassing the guard would make the contract instantly drainable in a single transaction.
Likelihood:
Requires a malicious or compromised verifier contract
Owner is trusted, so verifier swap is unlikely to be malicious
Low likelihood under normal operation
Impact:
If nonReentrant is ever removed, a malicious verifier can reenter claim() before state updates and drain the contract in a single transaction
nonReentrant is currently carrying two separate responsibilities — removing it for any reason exposes both reentrancy and replay vectors simultaneously
Correct CEI costs nothing to implement
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.