Project

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

Tier Full Validation in joinDAO

Summary

In the joinDAO function, the tier full validation may not be properly enforced, potentially allowing users to join a tier even if it is full, leading to incorrect behavior.

Finding Description

The issue arises from the line:

require(daos[daoMembershipAddress].tiers[tierIndex].amount > daos[daoMembershipAddress].tiers[tierIndex].minted, "Tier full.");

This validation checks if the number of members in the selected tier exceeds the tier's capacity. However, if the minted value is not correctly updated or if there are race conditions in the contract execution, this validation could fail to prevent additional users from joining a full tier.

This breaks the security guarantee of proper membership control, which is critical for ensuring that tiers do not exceed their capacity, potentially leading to issues like users being minted more tokens than allowed, or more than the intended number of members in a tier.

How Malicious Input Propagates:

  1. A malicious actor could repeatedly call joinDAO for a tier that they believe is not full (due to inconsistent state updates).

  2. If the state variable minted is not correctly updated after each mint or is manipulated via reentrancy, users may be able to mint additional tokens beyond the tier's defined capacity, leading to over-minting and the potential abuse of the membership system.

Vulnerability Details

  • Location: MembershipFactory.sol, joinDAO function.

  • Security Impact: The tier's full capacity check is bypassed under specific conditions (inconsistent state updates).

  • Type: Race Condition / State Inconsistency — When minted is not correctly updated or is delayed, malicious actors can exploit this window to bypass full tier validation.

Impact

This vulnerability can allow users to mint more tokens than intended, violating the designed membership limits of the DAO. If users are able to bypass the tier limit, it may lead to unexpected behaviors like excessive token distribution, violation of DAO rules, and even financial loss in a DAO context.

Severity Assessment:

  • Critical: This issue could lead to the issuance of more tokens than intended and break tier membership controls.

  • Exploitability: This issue could be exploited by attackers that are aware of the timing or state inconsistencies.

Proof of Concept

  1. Deploy the contract and create a DAO with multiple tiers.

  2. Attempt to join a full tier by calling the joinDAO function multiple times.

  3. Observe that if the minted count is not updated correctly, the user may still be allowed to mint additional tokens even if the tier is full.

Example of potentially faulty input:

// Assuming the tier limit is 100, but the `minted` value is not updated properly.
joinDAO(daoMembershipAddress, 0); // Should fail if tier 0 is full, but may succeed if `minted` is incorrect.

Recommendations

To fix this issue, ensure that the minted value is properly updated in a consistent manner. Consider using a reentrancy guard or mutex to prevent multiple state-changing operations from occurring simultaneously. Additionally, include an additional check to verify that the tier is indeed full before minting.

Fixed Code Snippet:

// In the joinDAO function:
require(daos[daoMembershipAddress].tiers[tierIndex].amount > daos[daoMembershipAddress].tiers[tierIndex].minted, "Tier full.");
// Ensure minting updates the state immediately and prevents further race conditions
daos[daoMembershipAddress].tiers[tierIndex].minted += 1;

Alternatively, a mutex to prevent reentrancy could be added:

// Add a simple mutex to prevent reentrancy
bool public mutex;
modifier noReentrancy() {
require(!mutex, "Reentrancy detected");
mutex = true;
_;
mutex = false;
}
function joinDAO(address daoMembershipAddress, uint256 tierIndex) external noReentrancy {
require(daos[daoMembershipAddress].tiers[tierIndex].amount > daos[daoMembershipAddress].tiers[tierIndex].minted, "Tier full.");
uint256 tierPrice = daos[daoMembershipAddress].tiers[tierIndex].price;
uint256 platformFees = (20 * tierPrice) / 100;
daos[daoMembershipAddress].tiers[tierIndex].minted += 1;
IERC20(daos[daoMembershipAddress].currency).transferFrom(_msgSender(), owpWallet, platformFees);
IERC20(daos[daoMembershipAddress].currency).transferFrom(_msgSender(), daoMembershipAddress, tierPrice - platformFees);
IMembershipERC1155(daoMembershipAddress).mint(_msgSender(), tierIndex, 1);
emit UserJoinedDAO(_msgSender(), daoMembershipAddress, tierIndex);
}

Conclusion:

The bug can be resolved by ensuring that the minted count is updated consistently and is protected from race conditions. Implementing a mutex or other mechanisms to ensure state consistency during critical updates is a vital step in fixing this issue.

Updates

Lead Judging Commences

0xbrivan2 Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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