SNARKeling Treasure Hunt

First Flight #59
Beginner FriendlyGameFiFoundry
100 EXP
Submission Details
Impact: medium
Likelihood: high

Duplicate treasure hash reduces claimable treasures

Author Revealed upon completion

Duplicate treasure hash reduces claimable treasures

Description

The ALLOWED_TREASURE_HASHES array in the circuit (circuits/src/main.nr:55-67) contains a duplicate entry. The hash -961435057317293580094826482786572873533235701183329831124091847635547871092 appears at both index 8 (line 64) and index 9 (line 66).

global ALLOWED_TREASURE_HASHES: [Field; 10] = [
// ... hashes 0-7 ...
-961435057317293580094826482786572873533235701183329831124091847635547871092,
// @audit duplicate
-961435057317293580094826482786572873533235701183329831124091847635547871092
];

Meanwhile, the deploy script (Deploy.s.sol:24-26) lists the correct 10th hash as -4417726114039171734934559783368726413190541565291523767661452385022043124552, which corresponds to treasure secret 9. This hash is missing from the circuit, meaning treasure 9 can never be claimed.

The contract is funded with 100 ETH (10 treasures x 10 ETH), but only 9 unique treasures are claimable. 10 ETH will be permanently locked unless the owner withdraws after MAX_TREASURES claims — but that can never happen either, since the claimed[_treasureHash] bug (line 89) prevents more than one claim regardless.

Risk

Likelihood: High

The duplicate is hardcoded in the circuit at compile time. Every deployment using this circuit will have only 9 unique treasures.

Impact: Medium

One treasure (10 ETH) becomes unclaimable. The contract expects 10 unique treasures but the circuit only validates 9.

Proof of Concept

  1. The ALLOWED_TREASURE_HASHES array has 10 entries but only 9 are unique.

  2. The missing hash from Deploy.s.sol:25 is -4417726114039171734934559783368726413190541565291523767661452385022043124552 (pedersen hash of secret 9).

  3. A player who finds treasure 9 cannot generate a valid proof because is_allowed() will never match the correct hash.

  4. 10 ETH remains locked in the contract.

Recommended Mitigation

Replace the duplicate entry at index 9 with the correct hash for treasure 9:

global ALLOWED_TREASURE_HASHES: [Field; 10] = [
// ... hashes 0-8 ...
- -961435057317293580094826482786572873533235701183329831124091847635547871092,
+ -4417726114039171734934559783368726413190541565291523767661452385022043124552
];

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!