Summary
The tier limit can be bypassed through upgrades, as the upgradeTier
function does not check whether the upgrade results in a full tier or not.
Vulnerability Details
In the upgradeTier
function shown below, there is no verification to ensure that the target tier has available capacity before allowing the upgrade. The check for upgrading tier is only check if the daoType is sponsored, and check if fromTierIndex
is valid (not exceeding noOfTiers
).
File: MembershipFactory.sol
152:
153:
154:
155: function upgradeTier(address daoMembershipAddress, uint256 fromTierIndex) external {
156: require(daos[daoMembershipAddress].daoType == DAOType.SPONSORED, "Upgrade not allowed.");
157: require(daos[daoMembershipAddress].noOfTiers >= fromTierIndex + 1, "No higher tier available.");
158: IMembershipERC1155(daoMembershipAddress).burn(_msgSender(), fromTierIndex, 2);
159: IMembershipERC1155(daoMembershipAddress).mint(_msgSender(), fromTierIndex - 1, 1);
160: emit UserJoinedDAO(_msgSender(), daoMembershipAddress, fromTierIndex - 1);
161: }
In contrast, the joinDAO
function correctly checks if a tier is full before allowing a user to join it. Without a similar check in upgradeTier
, users can exceed the limit by upgrading to a tier that may already be at capacity.
File: MembershipFactory.sol
140: function joinDAO(address daoMembershipAddress, uint256 tierIndex) external {
141: require(daos[daoMembershipAddress].noOfTiers > tierIndex, "Invalid tier.");
142: @> require(daos[daoMembershipAddress].tiers[tierIndex].amount > daos[daoMembershipAddress].tiers[tierIndex].minted, "Tier full.");
143: uint256 tierPrice = daos[daoMembershipAddress].tiers[tierIndex].price;
144: uint256 platformFees = (20 * tierPrice) / 100;
145: daos[daoMembershipAddress].tiers[tierIndex].minted += 1;
146: IERC20(daos[daoMembershipAddress].currency).transferFrom(_msgSender(), owpWallet, platformFees);
147: IERC20(daos[daoMembershipAddress].currency).transferFrom(_msgSender(), daoMembershipAddress, tierPrice - platformFees);
148: IMembershipERC1155(daoMembershipAddress).mint(_msgSender(), tierIndex, 1);
149: emit UserJoinedDAO(_msgSender(), daoMembershipAddress, tierIndex);
150: }
Impact
Users can bypass tier capacity limits through the upgrade process, potentially overloading a tier.
Tools Used
Manual analysis
Recommendations
Add a capacity check in the upgradeTier
function to ensure the target tier has available space before allowing the upgrade.