SNARKeling Treasure Hunt

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

Incorrect Use of Uninitialized Immutable Breaks Claim Tracking Logic

Author Revealed upon completion

Description

The contract incorrectly uses an uninitialized immutable variable _treasureHash when checking whether a treasure has already been claimed.

Instead of using the function parameter treasureHash, the contract performs the check using _treasureHash, which is never assigned in the constructor and therefore defaults to bytes32(0).

As a result, the duplicate claim protection does not correctly apply to individual treasures, and the mapping logic becomes inconsistent with the intended design.

This breaks the invariant that each treasure should be uniquely claimable only once.


Risk

The contract incorrectly uses an uninitialized immutable variable _treasureHash when checking whether a treasure has already been claimed.

Instead of using the function parameter treasureHash, the contract performs the check using _treasureHash, which is never assigned in the constructor and therefore defaults to bytes32(0).

This breaks the intended claim uniqueness logic and causes incorrect state tracking for treasure claims.

Impact:

  • Claim tracking is incorrect

  • Only bytes32(0) is checked for duplication

  • Real treasure hashes are not properly protected

  • Claim logic diverges from intended design

Severity:

High


๐Ÿงช Proof of Concept

The issue occurs because the contract checks an uninitialized storage variable instead of the input parameter.


Step 1 โ€” User submits a valid claim

claim(proof, treasureHash, recipient);

Step 2 โ€” Incorrect state check is performed

Inside the claim function:

if (claimed[_treasureHash]) revert AlreadyClaimed(treasureHash);

However:

  • _treasureHash is never initialized

  • It defaults to bytes32(0)


Step 3 โ€” Actual behavior

The contract always evaluates:

claimed[bytes32(0)]

instead of:

claimed[treasureHash]

Step 4 โ€” Result

  • Only the zero hash key is ever checked

  • Real treasure hashes are not properly tracked

  • Claim uniqueness enforcement is broken


๐Ÿ› ๏ธ Recommended Mitigation

The contract should correctly use the function parameter treasureHash for claim tracking.


โœ… Fix

Replace:

if (claimed[_treasureHash]) revert AlreadyClaimed(treasureHash);

With:

if (claimed[treasureHash]) revert AlreadyClaimed(treasureHash);

๐Ÿงน Optional Improvement

Remove the unused variable to prevent confusion:

bytes32 private immutable _treasureHash;

๐Ÿง  Expected Outcome After Fix

  • Each treasure is tracked correctly

  • Duplicate claims are properly prevented

  • Contract behavior matches intended design

Support

FAQs

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

Give us feedback!