Description:
The encodeTokenId and decodeTokenId functions in FestivalPass.sol are intended to pack a collectionId and an itemId into a single uint256 token ID and then reverse that operation. However, because there are no bounds checks on the sizes of collectionId and itemId, passing large values can cause bit overflow or overlap, leading to a mismatch between the original values and those returned by decodeTokenId.
Impact:
Data Corruption & Enumeration Errors: Mismatched IDs will lead to incorrect metadata lookups and reporting; loops over token IDs may skip or duplicate entries.
Asset Misattribution: Users may end up viewing or transferring the wrong NFT, potentially breaking ownership assumptions.
Security Risks: Attackers could craft out-of-range IDs to collide with valid IDs, spoofing token metadata or manipulating balances in enumeration functions like getUserMemorabiliaDetailed.
Proof of Concept:
Traces:
[13012] BeatTokenTest::testFuzz_EncodeDecodeEquals(2209565489602658888732503717266 [2.209e30], 8950265005652056424631159215985005930744246695058061687375512022564 [8.95e66])
├─ [0] VM::assume(true) [staticcall]
│ └─ ← [Return]
├─ [0] VM::assume(true) [staticcall]
│ └─ ← [Return]
├─ [1091] FestivalPass::encodeTokenId(2209565489602658888732503717266 [2.209e30], 8950265005652056424631159215985005930744246695058061687375512022564 [8.95e66]) [staticcall]
│ └─ ← [Return] 760826439674467069889829964273069317069602479457323566966187838221860 [7.608e68]
├─ [829] FestivalPass::decodeTokenId(760826439674467069889829964273069317069602479457323566966187838221860 [7.608e68]) [staticcall]
│ └─ ← [Return] 2235867954483924892482985086285 [2.235e30], 315535113242264627735032353991552740900 [3.155e38]
├─ [0] VM::assertEq(2235867954483924892482985086285 [2.235e30], 2209565489602658888732503717266 [2.209e30]) [staticcall]
│ └─ ← [Revert] assertion failed: 2235867954483924892482985086285 != 2209565489602658888732503717266
└─ ← [Revert] assertion failed: 2235867954483924892482985086285 != 2209565489602658888732503717266
Mitigation:
Enforce Input Bounds: Add require statements in encodeTokenId to ensure collectionId and itemId fit into their allocated bit-width (e.g., 64 bits each).
Use Safe Packing: Choose non-overlapping bit ranges (e.g., shift collectionId by 128 bits) or use Solidity’s ABI encoding (abi.encodePacked) followed by hashing if unique but inexact mapping is acceptable.
Document Limits: Clearly specify and enforce maximum collection and item counts to prevent overflow conditions.
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.