Snowman Merkle Airdrop

First Flight #42
Beginner FriendlyFoundrySolidityNFT
100 EXP
Submission Details
Impact: high
Likelihood: low

abi.encodePacked() Usage in `Snowman.sol::tokenURI` May Lead to Ambiguous Outputs

Author Revealed upon completion

abi.encodePacked() Usage in Snowman.sol::tokenURI May Lead to Ambiguous Outputs

Affected Contract & Function(s)

  • Contract: Snowman.sol

  • Function: tokenURI(uint256 tokenId)

  • Lines: 54 and 57

Description

The abi.encodePacked() function is used to concatenate arguments for creating the tokenURI. This method of serialization is unsafe when used with dynamic types like string because it can produce ambiguous results. Different sets of inputs can generate identical outputs, which can cause issues for off-chain systems (e.g., marketplaces and wallets) that parse or hash the URI.

Risk

The primary risk is ambiguous metadata representation. Systems that consume the tokenURI expect a unique and unambiguously structured URI.

Example:
abi.encodePacked("A", "BC") and abi.encodePacked("AB", "C") both produce the same output (0x414243).
Thus, different logical inputs for name and imageURI could theoretically result in the same final URI, leading to incorrect metadata indexing, caching, or display on third-party platforms.

Proof of Concept

The ambiguity can be demonstrated with a minimal contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract PackedEncodingPOC {
function demonstrateAmbiguity() public pure returns (bytes memory, bytes memory, bool) {
// Case 1: abi.encodePacked("A", "BC")
bytes memory packed1 = abi.encodePacked("A", "BC"); // -> 0x414243
// Case 2: abi.encodePacked("AB", "C")
bytes memory packed2 = abi.encodePacked("AB", "C"); // -> 0x414243
// The packed bytes are identical, and so are their hashes.
bool areHashesEqual = (keccak256(packed1) == keccak256(packed2)); // -> true
return (packed1, packed2, areHashesEqual);
}
}

Mitigation

It is strongly recommended to replace abi.encodePacked() with string.concat() for all string construction. This function avoids the ambiguities of packed encoding.

Support

FAQs

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