Beatland Festival

First Flight #44
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: medium
Likelihood: low
Invalid

The function `FestivalPass::uri` is at risk of encoding collisions.

If the URLs for player memorabilia are the same, it may lead to player dissatisfaction.

Description

  • Players who legitimately obtain commemorative NFTs may have a very low chance of receiving a URL that is identical to another player's.

// Override URI to handle collections and items
function uri(uint256 tokenId) public view override returns (string memory) {
// Handle regular passes (IDs 1-3)
if (tokenId <= BACKSTAGE_PASS) {
return string(abi.encodePacked("ipfs://beatdrop/", Strings.toString(tokenId)));
}
// Decode collection and item IDs
(uint256 collectionId, uint256 itemId) = decodeTokenId(tokenId);
// Check if it's a valid memorabilia token
if (collections[collectionId].priceInBeat > 0) {
// Return specific URI for this item
// e.g., "ipfs://QmXXX/metadata/5" for item #5
@> return string(abi.encodePacked(
collections[collectionId].baseUri,
"/metadata/",
Strings.toString(itemId)
));
}
return super.uri(tokenId);
}

Risk

Likelihood:

  • The use of the abi.encodePacked function may introduce the risk of encoding collisions.

Impact:

  • This can result in different token IDs being mapped to the same URL.

Proof of Concept

This risk can only be demonstrated when the system contains a large number of commemorative NFTs, but it is a real and valid concern.

Recommended Mitigation

Replace abi.encodePacked with string.concat in a reasonable and safe manner, as shown in the following code example:

// Override URI to handle collections and items
function uri(uint256 tokenId) public view override returns (string memory) {
// Handle regular passes (IDs 1-3)
if (tokenId <= BACKSTAGE_PASS) {
return string(abi.encodePacked("ipfs://beatdrop/", Strings.toString(tokenId)));
}
// Decode collection and item IDs
(uint256 collectionId, uint256 itemId) = decodeTokenId(tokenId);
// Check if it's a valid memorabilia token
if (collections[collectionId].priceInBeat > 0) {
// Return specific URI for this item
// e.g., "ipfs://QmXXX/metadata/5" for item #5
- return string(abi.encodePacked(
- collections[collectionId].baseUri,
- "/metadata/",
- Strings.toString(itemId)
- ));
+ return string.concat(
+ collections[collectionId].baseUri,
+ "/metadata/",
+ Strings.toString(itemId)
+ );
}
return super.uri(tokenId);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 25 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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