When updating a DAO membership with the updateDAOMembership function there is no checks made to make sure that the new tierConfigs[].amount is not less than the already existing dao.tiers[].minted. This will cause discrepencies in the contract while also breaking the invariants that the amount of minted tokens in a tier can not bypass the amount of tokens allowed to be minted and amount of maxMembers allowed in a DAO cannot be less than the amount of members in the DAO.
The EXTERNAL_CALLER role can update a dao with the updateDAOMembership function.
As observed from this function, there are no checks done to make sure than the new tierConfigs[].amount is greater than or equal to the already existing dao.tiers[].minted amount.
Consider the scenario where in a DAO's configuration, in Tier 3, the maximum allowed amount to be minted is 4 and members have joined this tier 4 times. Now Tier 3 is 4 out of 4 minted. The EXTERNAL_CALLER role now updates this DAO with the updateDAOMembership function and changes the Tier 3's maximum allowed minted amount to 2. Now Tier 3 will be 4 out of 2 minted and breaking the invariant where amount of minted tokens is greater than the maximum allowed amount that is mintable in this tier.
Another invariant that breaks here is the amount of maxMembers that can be in a DAO. This value is calculated by adding up the new tierConfigs[].amount values. Not making sure that the new amounts are greater than or equal to the already existing amount of minted tokens will lead to the new maxMembers value being less than the amount of members that already exist, leading to this invariant also breaking. maxMembers value will store a value that is less than the amount of members in the DAO.
The issues that are caused here are:
Before the update, in order for new users to join Tier 3 they would have to wait for any user in Tier 3 to call the upgradeTier function which would empty out 2 slots for new users to join. However, because the allowed amount is not validated to be greater than or equal to already existing amount , in order for new users to join this tier they will have to wait for two different upgradeTier function calls.
maxMembers state variable will store a value that is less than already existing number of members.
Maximum amount of tokens that can be minted in a tier will be less than the amount of tokens that are already minted.
1) Implement a new getter function in MembershipFactory.sol to make tests easier.
2) Implement a mock WETH contract for testing inside the test folder.
3) Implement and run the following test to observe the vulnerability
Impact: Medium
Likelihood: Low, requires the EXTERNAL_CALLER role to update the DAO with a new amount that is less than the existing minted amount.
Manual review, foundry
Implement a new check in the for loop in the updateDAOMembership function to make sure that the new tierConfigs[].amount is greater than or equal to the already existing dao.tiers[].minted.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.