Snowman Merkle Airdrop

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

Incorrect Message Hash will lead to serious issues in EIP-712 signature verification

Root + Impact

An incorrect message hash used in the SnowmanAirdrop contract will result in a mismatch with the off-chain signer and also lead to serious issues in EIP-712 signature verification

Description

  • There are instances where data could be hashed incorrectly. The First instance includes a typo in SnowmanAirdrop::MESSAGE_TYPEHASH and the second instance includes hashing Snowman::AirdropClaim struct directly in Snowman::getMessagHash function, which is not EIP712 compliant.

@> bytes32 private constant MESSAGE_TYPEHASH = keccak256("SnowmanClaim(addres receiver, uint256 amount)");
function getMessageHash(address receiver) public view returns (bytes32) {
if (i_snow.balanceOf(receiver) == 0) {
revert SA__ZeroAmount();
}
uint256 amount = i_snow.balanceOf(receiver);
return _hashTypedDataV4(
@> keccak256(abi.encode(MESSAGE_TYPEHASH, SnowmanClaim({receiver: receiver, amount: amount})))
);

Risk

Likelihood:

This Vulnerability will occur when this contract interacts with off-chain components like a frontend asking users to sign a message, A backend, or a script that uses ethers.js, viem to generate a signature or third-party wallet (like MetaMask, Safe, Ledger) that signs structured data

Impact:

  • It can result in a potential fund lock or Denial of Service, where off-chain users with correct signatures can't claim

Recommended Mitigation

To adhere to EIP 712 standards, in SnowmanAirdrop::getMessageHash function, the Protocol should ensure that each field in the struct is individually encoded, **not **the struct as a whole

Secondly, add the correct message type hash to SnowmanAirdrop::MESSAGE_TYPEHASH

- bytes32 private constant MESSAGE_TYPEHASH = keccak256("SnowmanClaim(addres receiver, uint256 amount)");
+ bytes32 private constant MESSAGE_TYPEHASH = keccak256("SnowmanClaim(address receiver, uint256 amount)");
- function getMessageHash(address receiver) public view returns (bytes32) {
if (i_snow.balanceOf(receiver) == 0) {
revert SA__ZeroAmount();
}
uint256 amount = i_snow.balanceOf(receiver);
return _hashTypedDataV4(
- keccak256(abi.encode(MESSAGE_TYPEHASH, SnowmanClaim({receiver: receiver, amount: amount})))
);
}
+ function getMessageHash(address receiver, AirdropClaim memory claim) public view returns (bytes32) {
if (i_snow.balanceOf(receiver) == 0) {
revert SA__ZeroAmount();
}
uint256 amount = i_snow.balanceOf(receiver);
return _hashTypedDataV4(
+ keccak256(abi.encode(MESSAGE_TYPEHASH, claim.receiver, claim.amount)) //EIP712 complaint hash
);
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge 23 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Appeal created

0xtory Submitter
22 days ago
yeahchibyke Lead Judge
22 days ago
yeahchibyke Lead Judge 20 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.