Project

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

Inconsistent Membership Validation in MembershipFactory Allows Unauthorized DAO Membership Expansion

Summary

The MembershipFactory contract has a vulnerability that leads to a critical violation of membership constraints in the DAO system. The inconsistent validation logic between creation and updates allows circumvention of initially established membership limits, enabling unauthorized expansion of DAO membership capacity. This undermines the core membership control mechanism of the DAO, potentially affecting tokenomics, voting power distribution, and overall DAO governance structure. The ability to arbitrarily increase membership limits without proper validation poses a serious risk to the DAO's operational integrity and could be exploited to dilute existing member value or manipulate DAO participation parameters.

The issue stems from contradictory logic implementations between the DAO creation and update functions. During creation, the contract enforces strict validation ensuring total tier membership amounts cannot exceed the specified maxMembers limit. However, the update function inverts this relationship by automatically increasing maxMembers when tier amounts exceed it. This logical inconsistency creates a fundamental break in the contract's state invariants.

The following code snippets demonstrate this contradiction:

In createNewDAOMembership:

https://github.com/Cyfrin/2024-11-one-world/blob/main/contracts/dao/MembershipFactory.sol#L55

uint256 totalMembers = 0;
for (uint256 i = 0; i < tierConfigs.length; i++) {
totalMembers += tierConfigs[i].amount;
}
require(totalMembers <= daoConfig.maxMembers, "Sum of tier amounts exceeds maxMembers.");

While in updateDAOMembership:

https://github.com/Cyfrin/2024-11-one-world/blob/main/contracts/dao/MembershipFactory.sol#L100

uint256 maxMembers = 0;
for (uint256 i = 0; i < tierConfigs.length; i++) {
dao.tiers.push(tierConfigs[i]);
maxMembers += tierConfigs[i].amount;
}
if(maxMembers > dao.maxMembers){
dao.maxMembers = maxMembers;
}

This implementation allows the update function to bypass the fundamental membership constraints established during creation, effectively nullifying the initial validation mechanisms.

Recommended Fix

function updateDAOMembership(string calldata ensName, TierConfig[] memory tierConfigs)
external onlyRole(EXTERNAL_CALLER) returns (address) {
address daoAddress = getENSAddress[ensName];
require(tierConfigs.length <= TIER_MAX, "Invalid tier count.");
require(tierConfigs.length > 0, "Invalid tier count.");
require(daoAddress != address(0), "DAO does not exist.");
DAOConfig storage dao = daos[daoAddress];
if(dao.daoType == DAOType.SPONSORED){
require(tierConfigs.length == TIER_MAX, "Invalid tier count.");
}
uint256 totalMembers = 0;
for (uint256 i = 0; i < tierConfigs.length; i++) {
if (i < dao.tiers.length) {
require(tierConfigs[i].amount >= dao.tiers[i].minted, "New amount below minted tokens");
tierConfigs[i].minted = dao.tiers[i].minted;
}
totalMembers += tierConfigs[i].amount;
}
require(totalMembers <= dao.maxMembers, "Sum of tier amounts exceeds maxMembers");
delete dao.tiers;
for (uint256 i = 0; i < tierConfigs.length; i++) {
dao.tiers.push(tierConfigs[i]);
}
dao.noOfTiers = tierConfigs.length;
return daoAddress;
}

The fix maintains consistency with the creation function's validation logic and adds necessary checks for minted tokens. It removes the automatic maxMembers increase and enforces the original membership constraints throughout the DAO's lifecycle. Additional validations ensure new tier amounts cannot be set below already minted tokens, preventing potential inconsistencies in the membership state.

Updates

Lead Judging Commences

0xbrivan2 Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Design choice
0xbrivan2 Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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