Snowman Merkle Airdrop

AI First Flight #10
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: medium
Likelihood: high
Invalid

Signature Depends on Mutable Snow Balance Causing Unexpected Claim Failure

Root + Impact

Description

Normal Behavior

The protocol allows a Snow token holder to authorize another party to claim Snowman NFTs
on their behalf using an ECDSA signature. A valid signature is expected to represent a stable
authorization that remains valid until it is used or explicitly revoked.

Specific Issue

The signed message includes the Snow token balance of the receiver, which is dynamically
retrieved at claim time using balanceOf(receiver). Since Snow balances are mutable, the
message hash reconstructed during verification may differ from the message that was originally
signed.

As a result, signatures can become unexpectedly invalid through normal balance changes,
preventing legitimate claims from succeeding.

In SnowmanAirdrop.sol:
@> uint256 amount = i_snow.balanceOf(receiver);
@> bytes32 digest = _hashTypedDataV4(
@> keccak256(
@> abi.encode(
@> MESSAGE_TYPEHASH,
@> receiver,
@> amount
@> )
@> )
@> );
@> address signer = ECDSA.recover(digest, v, r, s);
The `amount` value included in the signed message is not fixed at signing time and is instead
derived from the receiver’s current Snow balance during claim verification.

RISK

Likelihood:

  1. Snow balances are expected to change frequently due to earning, purchasing, transferring,
    or staking Snow tokens.

  2. Signature creation and claim submission are not atomic, making balance drift a normal
    operational condition.

Impact:

  1. Previously valid signatures can become unusable without warning, causing legitimate
    claims to fail.

  2. Users relying on third-party claim execution may be permanently blocked from claiming
    their Snowman NFTs.

Proof of Concept

1. Alice holds 100 Snow tokens.
2. Alice signs an authorization message allowing a relayer to claim on her behalf.
- Signed message includes (Alice, 100).
3. Before the relayer submits the claim, Alice’s Snow balance changes to 120 due to normal
protocol usage.
4. The relayer submits the signed message to the SnowmanAirdrop contract.
5. During verification, the contract computes:
- amount = balanceOf(Alice) = 120
6. The reconstructed message hash does not match the originally signed hash.
7. Signature verification fails, and the claim is rejected.
This failure occurs without any malicious behavior and results solely from normal balance
changes between signing and claim execution.

Recommended Mitigation

Avoid including mutable runtime values in signed messages.

For example:

- remove this code
- uint256 amount = i_snow.balanceOf(receiver);
+ add this code
+ uint256 amount = signedAmount;
Alternatively, bind the signature to an immutable snapshot value or include a nonce and
explicit expiry to ensure predictable signature validity.
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 11 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!