Normal behavior: Each treasureHash should be claimable at most once. The claimed mapping should block a second successful claim for the same hash after a valid proof pays out once.
Problem: The replay check reads claimed[_treasureHash] where _treasureHash is an immutable that is never set in the constructor, while _markClaimed writes claimed[treasureHash]. The guard slot never tracks real claims, so the same valid proof and hash can pay out repeatedly until claimsCount reaches MAX_TREASURES.
Likelihood:
A participant with one valid proof and matching public inputs calls claim in a loop until the contract balance is exhausted or claimsCount hits the cap.
The mistaken guard slot stays false for user-supplied hashes, so every repeat passes the replay check after proof verification succeeds.
Impact:
Up to MAX_TREASURES * REWARD ETH can be sent to the same recipient using one proof and one hash.
Honest hunters lose intended per-treasure fairness because one hash can consume the full claim budget.
The replay guard reads claimed[_treasureHash] (immutable never set) while _markClaimed sets claimed[treasureHash], so the guard slot never flips for a real treasureHash. The Foundry test below loads a valid fixture proof once, then calls claim ten times with the same proof, treasureHash, and recipient. Prerequisites: from the contest repo root, run circuits/scripts/build.sh once so contracts/test/fixtures/proof.bin and public_inputs.json exist. How to run: forge test --match-test testPoC_RepeatedClaimDrainsAllRewards -vv. Expected result: test passes; claimsCount reaches 10, contract balance goes to zero, recipient receives 10 * REWARD.
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.