Snowman Merkle Airdrop

First Flight #42
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: high
Valid

[H-1]: Incorrect MESSAGE_TYPEHASH Definition

Root + Impact

Description

Normal Behavior:

The SnowmanAirdrop contract uses EIP-712 signatures to validate a user's claim before allowing them to mint a Snowman NFT. This involves hashing a struct and verifying the signer's signature using EIP-712 domain seperator and ECDSA.

Specific Issue:

The contract incorrectly defines the MESSAGE_TYPEHASH for the SnowClaim struct as:

@> bytes32 private constant MESSAGE_TYPEHASH = keccak256("SnowmanClaim(addres receiver, uint256 amount)");

The word addres is a messpelling of address, which leads to a hash mismatch when generating EIP-712 signatures. As a result, all signatures will be invalid, and no user will be able to successfully claim their Snoman NFTs.

Risk

Likelihood:

  • This error will occur every time a user tries to claim using a correctly signed message based on the real SnowmanClaim(address receiver, uint256 amount) struct.

  • Developers or end users signing messages off-chain using the correct sturct definition will always fail to verify on-chain.

Impact:

  • Sinature verification fails on all claims, effectively disabling the airdrop.

  • Users will waste gas on failed claim attempts, leading to poor UX and trust issues.

Proof of Concept

Here is the PoC demonstrating the issue given below:

Note: make getter function in the SnowmanAirdrop to get the MESSAGE_TYPEHASH or just copy paste the following in the AirdropContract

function getMessageTypeHash() external pure returns (bytes32) {
return MESSAGE_TYPEHASH;
}

Copy the given PoC code to the TestSnowmanAirdrop.t.sol:

function testMessageTypeHashMatch() public view {
bytes32 expected = keccak256("SnowmanClaim(address receiver, uint256 amount)");
assert(airdrop.getMessageTypeHash() != expected);
}

Recommended Mitigation

- bytes32 private constant MESSAGE_TYPEHASH = keccak256("SnowmanClaim(addres receiver, uint256 amount)");
+ bytes32 private constant MESSAGE_TYPEHASH = keccak256("SnowmanClaim(address receiver, uint256 amount)");
  • After this fix, Signatures generated off-chain with the correct struct type will match the digest produced on-chain, allowing valid claims to succeed.

Updates

Lead Judging Commences

yeahchibyke Lead Judge 14 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Inconsistent MESSAGE_TYPEHASH with standard EIP-712 declaration

A typo in the `MESSAGE_TYPEHASH` variable of the `SnowmanAirdrop` contract will prevent signature verification claims. Used `addres` instead of `address`

Support

FAQs

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