Root + Impact
Description
The SnowmanAirdrop contract uses EIP-712 typed data signatures to verify that users have authorized the claiming of their Snowman NFTs.
The MESSAGE_TYPEHASH is a critical component of this verification process, as it defines the structure of the data being signed.
Issue:
There is a critical typo in the MESSAGE_TYPEHASH constant definition:
bytes32 private constant MESSAGE_TYPEHASH = keccak256("SnowmanClaim(@>addres<@ receiver, uint256 amount)");
The word "address" is misspelled as "addres" (missing the second 's'). This typo means that the hash used for signature verification will not match the hash that was used to generate the signature, causing all signature verifications to fail.
When a user attempts to claim their Snowman NFT, the _isValidSignature function will always return false because the hash calculated during verification doesn't match the hash used when signing the message. This will cause the transaction to revert with the SA__InvalidSignature() error.
Risk
Likelihood:
Impact:
-
Impact 1 // All users will be unable to claim their Snowman NFTs through the airdrop contract
-
Impact 2 // The core functionality of the protocol is completely broken until a new contract is deployed with the correct type hash
Proof of Concept
function demonstrateSignatureFailure() public {
address user = address(0x123);
bytes32 correctTypeHash = keccak256("SnowmanClaim(address receiver, uint256 amount)");
bytes32 correctHash = keccak256(abi.encode(correctTypeHash, user, 100));
bytes32 contractTypeHash = keccak256("SnowmanClaim(addres receiver, uint256 amount)");
bytes32 contractHash = keccak256(abi.encode(contractTypeHash, user, 100));
assert(correctHash != contractHash);
}
Recommended Mitigation
bytes32 private constant MESSAGE_TYPEHASH = keccak256("SnowmanClaim(addres receiver, uint256 amount)");
bytes32 private constant MESSAGE_TYPEHASH = keccak256("SnowmanClaim(address receiver, uint256 amount)");