Improper use of abi.encodePacked() in metadata construction introduces potential hash collision risks that could lead to NFT identity forgery or off-chain verification failures.
In ERC721 contracts, the tokenURI() function generates metadata for an NFT that is used to render name, image, owner, and other traits. This data is typically constructed as a JSON string and base64 encoded.
In the WeatherNft::tokenURI()
function, abi.encodePacked() is used to concatenate strings when constructing the metadata. While this may seem efficient, it can lead to hash collisions when used in combination with keccak256() or other hash-based comparisons. This is a known risk due to the ambiguous, non-delimited encoding produced by abi.encodePacked.
Likelihood:
Developers frequently use abi.encodePacked() for string concatenation, and it may later be reused in ways involving hashing (e.g., caching metadata hashes, verifying signatures).
No delimiter or length information is preserved between arguments, so multiple different inputs can yield the same packed byte string.
Impact:
An attacker could craft multiple distinct inputs (e.g., addresses or image URIs) that collide to the same hash, which may break future assumptions about uniqueness.
If tokenURI() output is ever hashed for off-chain verification, NFTs with different owners or metadata could produce the same result, enabling forgery or misrepresentation.
Created a simple Foundry test showing that different inputs produce the same abi.encodePacked() result, which would produce the same base64 metadata hash if used inside tokenURI():
abi.encode(...) is safer and unambiguous:
It adds length prefixes and type separation.
Prevents subtle collisions if tokenURI() output is ever hashed, compared, or verified off-chain.
This is informational. The `user` and the `image` are always different for each `tokenURI`.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.