Beatland Festival

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

Unbounded Loop in `getUserMemorabiliaDetailed` leads to Denial of Service

Description

  • The getUserMemorabiliaDetailed function is designed to return all memorabilia tokens owned by a user, iterating over all collections and items.

  • The function uses nested unbounded loops over all collection IDs and all item IDs within each collection, with no upper limit enforced

function getUserMemorabiliaDetailed(address user) external view returns (
uint256[] memory tokenIds,
uint256[] memory collectionIds,
uint256[] memory itemIds
) {
// First, count how many memorabilia they own
uint256 count = 0;
for (uint256 cId = 1; cId < nextCollectionId; cId++) {
for (uint256 iId = 1; iId < collections[cId].currentItemId; iId++) {
@> uint256 tokenId = encodeTokenId(cId, iId);
if (balanceOf(user, tokenId) > 0) {
count++;
}
}
}
// ... (second unbounded nested loop)
}

Risk

Likelihood:
This will occur whenever a user or contract calls getUserMemorabiliaDetailed after a large number of collections and/or items have been created.
As the number of collections and items grows, the function will require more gas, eventually exceeding the block gas limit.
Impact:
The function will revert due to out-of-gas, making it unusable for users with many memorabilia tokens.
This can cause frontends or other contracts relying on this function to break or become unresponsive.
Proof of Concept

// After creating 1000 collections with 1000 items each, call getUserMemorabiliaDetailed(user)
// The call will revert due to exceeding the block gas limit.
festivalPass.getUserMemorabiliaDetailed(user);

Recommended Mitigation

- for (uint256 cId = 1; cId < nextCollectionId; cId++) {
- for (uint256 iId = 1; iId < collections[cId].currentItemId; iId++) {
- uint256 tokenId = encodeTokenId(cId, iId);
- if (balanceOf(user, tokenId) > 0) {
- count++;
- }
- }
- }
+ // Add pagination or limit the number of iterations per call.
+ // Alternatively, require off-chain indexing for large collections.
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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