Beatland Festival

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

Passes Can Be Fractionalized Due to ERC1155 Semantics

Description

The contract uses the ERC1155 standard to represent festival passes (General, VIP, Backstage). ERC1155 tokens are fungible per token ID by default, meaning each pass type is just a balance of a given token ID.

ERC1155 allows balances to be split and transferred in arbitrary amounts, including fractions (e.g., 0.5, 0.01), unless explicitly prevented.

Impact

  • Fractional Passes:

Users can transfer a fraction of a pass (e.g., 0.5 VIP pass) to another address.

  • Access Control Bypass:

The hasPass(address user) function only checks if the user’s balance for a pass ID is greater than zero. Thus, any address with a tiny fraction of a pass will be considered a valid pass holder.

  • Potential Abuse:

A single pass can be split into many fractions and distributed to multiple addresses, all of which would be able to access pass-holder features (e.g., attend performances, claim rewards).

function buyPass(uint256 collectionId) external payable {
// Must be valid pass ID (1 or 2 or 3)
require(collectionId == GENERAL_PASS || collectionId == VIP_PASS || collectionId == BACKSTAGE_PASS, "Invalid pass ID");
// Check payment and supply
require(msg.value == passPrice[collectionId], "Incorrect payment amount");
require(passSupply[collectionId] < passMaxSupply[collectionId], "Max supply reached");
// Mint 1 pass to buyer
_mint(msg.sender, collectionId, 1, "");
}
// Check if user owns any pass
function hasPass(address user) public view returns (bool) {
return balanceOf(user, GENERAL_PASS) > 0 ||
balanceOf(user, VIP_PASS) > 0 ||
balanceOf(user, BACKSTAGE_PASS) > 0;
}


Risk : HIGH

Likelihood: HIGH

Example Scenario

  1. User A buys 1 VIP pass (token ID 2).

  1. User A transfers 0.01 of the VIP pass to User B.

  1. User B now has a balance of 0.01 for VIP pass.

  1. User B passes the hasPass check and can access all VIP pass-holder features.


Recommended Mitigation

Override the _beforeTokenTransfer hook in ERC1155 to enforce this for pass IDs.

function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal override {
for (uint256 i = 0; i < ids.length; i++) {
uint256 id = ids[i];
if (id == GENERAL_PASS || id == VIP_PASS || id == BACKSTAGE_PASS) {
require(amounts[i] % 1 == 0, "Passes must be whole units");
require(amounts[i] >= 1, "Cannot transfer zero or fractional pass");
}
}
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 month ago
inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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