Summary
The validation of fromTierIndex parameter only validates the upper bound, but not the lower bound.
Vulnerability Details
The function upgradeTier code is the following:
function upgradeTier(
address daoMembershipAddress,
uint256 fromTierIndex
) external {
require(
daos[daoMembershipAddress].daoType == DAOType.SPONSORED,
"Upgrade not allowed."
);
require(
daos[daoMembershipAddress].noOfTiers >= fromTierIndex + 1,
"No higher tier available."
);
IMembershipERC1155(daoMembershipAddress).burn(
_msgSender(),
fromTierIndex,
2
);
IMembershipERC1155(daoMembershipAddress).mint(
_msgSender(),
fromTierIndex - 1,
1
);
emit UserJoinedDAO(_msgSender(), daoMembershipAddress, fromTierIndex - 1);
}
The only statement which validates the tier level is
require(
daos[daoMembershipAddress].noOfTiers >= fromTierIndex + 1,
"No higher tier available."
);
However the lower bound is not validated. The tiers range is from 1 to 6 inclusive [1, 6], therefore if we pass value 0 as the parameter fromTierIndex is of type uint256 this check is bypassed.
The function will however fail on this code:
IMembershipERC1155(daoMembershipAddress).mint(
_msgSender(),
fromTierIndex - 1,
1
);
Because underflow will hapen. On this version of solidity the transaction will revert. However first we burned the tokens:
IMembershipERC1155(daoMembershipAddress).burn(
_msgSender(),
fromTierIndex,
2
);
This can be expensive for users and gas consumption can be high.
Impact
Wasting users gas
Tools Used
manual review
Recommendations
Validate also the lower bound
function upgradeTier(
address daoMembershipAddress,
uint256 fromTierIndex
) external {
require(
daos[daoMembershipAddress].daoType == DAOType.SPONSORED,
"Upgrade not allowed."
);
+ require(
+ fromTierIndex >= 1, "Invalid tier"
+ )
require(
daos[daoMembershipAddress].noOfTiers >= fromTierIndex + 1,
"No higher tier available."
);
IMembershipERC1155(daoMembershipAddress).burn(
_msgSender(),
fromTierIndex,
2
);
IMembershipERC1155(daoMembershipAddress).mint(
_msgSender(),
fromTierIndex - 1,
1
);
emit UserJoinedDAO(_msgSender(), daoMembershipAddress, fromTierIndex - 1);
}