Typical governance vulnerabilities:
from DAO building to DAO smart contract audit

Understanding Decentralized Autonomous Organizations (DAOs)

Decentralized Autonomous Organizations (DAOs) are blockchain-based entities that function without a central authority, and they are governed by rules encoded as smart contracts. The foundation of a DAO is its smart contract, a digital agreement that facilitates operations and enforces the organization's rules transparently. While DAOs offer exciting possibilities, their decentralized nature makes them particularly susceptible to security threats, and thus managing security becomes vital.

Key security concerns for DAOs involve vulnerabilities in the smart contract code, which can result in significant financial loss or misuse of governance rights. A notable example was the infamous DAO hack in 2016, where a flaw in the smart contract allowed an attacker to drain millions worth of Ethereum from the DAO. This incident underscored the importance of having smart contract audits to detect and fix such vulnerabilities before they can be exploited.

Other potential vulnerabilities include reentrancy attacks, where a called contract hijacks the calling contract, causing it to behave in unintended ways or front-running, where someone exploits the public visibility of pending transactions to their advantage.
The decentralized governance of DAOs also opens up potential attack vectors. For instance, a '51% attack' can occur when a single entity gains control of the majority of the voting rights, leading to dictatorial decision-making.

Securing a DAO also involves maintaining a robust identity and access management system, ensuring secure multi-signature wallets for holding funds, and implementing secure voting mechanisms to prevent vote manipulation.

In essence, the security of a DAO is paramount to its functioning and credibility. It's crucial to conduct rigorous smart contract audits, utilize secure coding practices, and build strong governance models to manage and mitigate these potential threats. This ensures the sustainability and trustworthiness of the DAO, encouraging broader participation and engagement. Let’s discuss typical DAO building vulnerabilities.
Looking for support with deployment or smart contract audit?

Check our proprietary service
Deployment Check

We would be happy to discuss any of your security and deployment requests

Typical DAO Building Vulnerabilities and How to Mitigate Them

Let’s explore some typical DAO vulnerabilities and discuss potential solutions to mitigate these risks.

Governance Attacks

One of the most significant vulnerabilities in DAOs are governance attacks. These occur when an attacker acquires voting power through legitimate means, such as buying tokens on the open market, but uses that power to manipulate the protocol for their own benefit. These attacks are purely "in-protocol," meaning they can't be addressed through cryptography. Instead, they require thoughtful mechanism design.
Examples of such attacks include the Steemit incident, where Justin Sun acquired a significant amount of STEEM tokens to control the network, and the Beanstalk case, where an attacker used a flash loan to seize $182 million of Beanstalk’s reserves. These incidents highlight the need for robust governance mechanisms to prevent such attacks

The Indistinguishability Problem

The indistinguishability problem is a fundamental challenge in DAO governance. Market mechanisms for token allocation fail to distinguish between users who want to contribute to a project and attackers who aim to disrupt it. Both groups are willing to buy large quantities of tokens at increasingly high prices, making them behaviorally indistinguishable from a market perspective.

Framework for Assessing and Addressing Vulnerability

To analyze the vulnerability different projects face, theres is a common framework captured by the following equation:
  • Profit =

  • (Value of Attack)

  • -(Cost of Acquiring Voting Power)

  • -(Cost of Executing Attack)

For a protocol to be considered secure against governance attacks, an attacker’s profit should be negative. This equation can guide the evaluation of different design choices to reduce the incentives to exploit the protocol.

Decreasing the Value of Attacks

Designers can limit the value of attacks by limiting the scope of what governance can do. For instance, if governance only includes the power to change certain parameters in a project, the scope of potential attacks is much narrower than when governance allows full control of the governing smart contract.

Increasing the Cost of Acquiring Voting Power

A project can take steps to make it harder to acquire the voting power needed for an attack. This can be done by incentivizing staking, or by giving tokens standalone value beyond pure governance. The more value accrues to token holders, the more aligned they become with the project's success.

Increasing the Cost of Executing Attacks

It's possible to introduce frictions that make it harder for an attacker to exercise voting power even once they have acquired tokens. For example, designers could require some sort of user authentication for participating in votes, such as a KYC (know your customer) check or reputation score threshold.
DAOs must strike a balance between openness to community changes and security against malicious proposals. The solutions proposed here fall on a spectrum between fully decentralized governance and partially sacrificing some ideals of decentralization for the overall health of the protocol. By understanding these vulnerabilities and implementing the suggested solutions, DAOs can become more secure and resilient against potential attacks. Additionally, there are numerous vulnerabilities in smart contracts for DAO protocols. Let us discuss them in greater detail.
In Mundus Security we put a lot of attention to DAO Governance structure and constantly analyse the best market practises. You could find our previous overview of DAOs anti-hacks behaviour in Four ways how DAO community could increase security of the protocol.

Potential Smart Contract DAO Vulnerabilities and Mitigations by Smart Contract Audits

DAOs function within a blockchain environment and are governed by voting mechanisms. Among these, token-based voting is the most prevalent. In this system, a DAO member proposes a change, and other token holders express their approval by casting votes with their tokens. The proposal is executed once it achieves the required quorum.

However, this approach has been criticized by prominent figures such as Vitalik Buterin for several reasons:
  1. Conflicts of interest can arise for token holders who also possess tokens from other DeFi platforms interacting with the platform in question.
  2. Token-based voting is inherently vulnerable to attacks such as vote buying, vote lending, and collusion among whales.
  3. The system is susceptible to complex Game-Theoretic Attacks.
  4. Wealthy participants, or "whales," can manipulate decisions more effectively than a large group of small-holders.
  5. Token-based governance may favor the interests of token holders over other community members.

In addition to these non-technical issues, there are also technical vulnerabilities that can arise due to programming errors or insufficient understanding of blockchain operations.

Several DAOs, including Aragon-based DAOs, X-DAO, Nexus Mutual, Showball Finance, Pickle Finance, Spirit Swap, and Keep3r Network, and many others employ token-based voting. Let’s explore the technical vulnerabilities that can occur in token-based voting based on these and several others protocols.

Attack #1: Flash Loan

A DAO may be vulnerable if an attacker can vote and execute a proposal within the same block (e.g., via an emergency method). This type of vulnerability has been observed in projects like Beanstalk and MakerDAO.
Possible mitigation:
Aragon uses MiniMeToken's balanceOfAt() function to calculate a user's balance one block before the proposal was created, effectively preventing flash loan attacks.
Nexus Mutual divides proposals into those that only the advisory board can vote on and those that ordinary members can vote on. In the advisory board voting, each participant's weight is equal to one. A member voting is a standard token-based voting.
A proposal can be voted on and executed in one transaction if all other members have already voted. However, the ability to transfer tokens is locked for the next seven days after each vote, making flash loan attacks challenging.
function canCloseProposal(uint _proposalId)
    ...
    if (numberOfMembers == proposalVoteTally[_proposalId].voters
      || dateUpdate.add(_closingTime) <= now)
      return 1;

Attack #2: Incorrect Re-Vote Handling in DAOs

A potential vulnerability in DAOs can occur if a contract permits a user to re-vote on a proposal but fails to correctly subtract the user's previous vote.

It is advisable to check for the following risky scenarios:
  1. Voting for a non-existent proposal.
  2. Voting, transferring tokens, then voting again.
  3. Voting for a proposal in the same block it was created.
  4. Voting with malformed parameters but for the same proposal ID.
  5. Replaying an off-chain transaction.

These types of vulnerabilities have been previously encountered in projects like MakerDAO and KP3R Network.
Possible mitigation:
In Aragon, re-voting is allowed, but the previous voting power is correctly added/subtracted.
uint256 voterStake = token.balanceOfAt(_voter, vote_.snapshotBlock);
VoterState state = vote_.voters[_voter];

if (state == VoterState.Yea) {
    vote_.yea = vote_.yea.sub(voterStake);
} else if (state == VoterState.Nay) {
    vote_.nay = vote_.nay.sub(voterStake);
}
Aragon also prevents voting for a non-existent proposal with a voteExists modifier.
function vote(
    uint256 _voteId,
    bool _supports,
    bool _executesIfDecided
) external voteExists(_voteId)
In X-DAO, voting occurs off-chain, and there is no mechanism to re-vote on the same proposal. A signed vote cannot be counted twice.
require(!_hasDuplicate(signers), "DAO: signatures are not unique.");
Replay attacks are also prevented as it's impossible to replay a user's signed vote on a different Ethereum chain, another X-DAO instance, or another proposal with a different nonce.
function getTxHash
...
return
    keccak256(abi.encode(
        address(this),
        _target,
        _data,
        _value,
        _nonce,
        _timestamp,
        block.chainid
    ));
}
In Nexus Mutual, it's impossible to vote for a non-existent proposal or to vote for a proposal more than once.
function submitVote(uint _proposalId, uint _solutionChosen) external {
    ...
    require(allProposalData[_proposalId].propStatus == uint(Governance.ProposalStatus.VotingStarted), "Not allowed");
}

function _submitVote(uint _proposalId, uint _solution) internal {
    ...
    require(memberProposalVote[msg.sender][_proposalId] == 0, "Not allowed");
    ...
    memberProposalVote[msg.sender][_proposalId] = totalVotes;
}

Attack #3: Insufficient Proposal Validation in DAOs

A potential vulnerability in DAOs can occur if a proposal's properties are not fully validated, opening up opportunities for social engineering attacks. An attacker could create a harmful proposal that appears harmless.
Consider the following questions:
  1. Can an attacker provide an arbitrary script or calldata in a proposal?
  2. How is a proposal displayed on a website?
  3. Is it difficult for a regular user to determine what the script of a proposal actually does?
  4. Can an attacker provide an arbitrary benign description in a malicious proposal?
Weak validation has been previously encountered in projects like Beanstalk and Nexus Mutual.
Possible mitigation:
In Aragon, a new proposal can take an arbitrary execution script and metadata.
function newVote(bytes _executionScript, string _metadata) external auth(CREATE_VOTES_ROLE) returns (uint256 voteId)
The metadata is emitted but not stored, implying that a backend will parse the blockchain for events to display a proposal author address and description.
emit StartVote(voteId, msg.sender, _metadata);
Therefore, it's possible to provide an arbitrary execution script, leaving the responsibility of verifying the data to the voters.
In Snowball Finance, a new proposal takes several arguments and stores all of them, including msg.sender, in the contract's storage.
function propose(
    string calldata _title,
    string calldata _metadata,
    uint256 _votingPeriod,
    address _target,
    uint256 _value,
    bytes memory _data
)
There are no limits on the calldata, so the responsibility for verifying the data falls on the voters.

Attack #4: Absence of Transfer Validation

A token locking mechanism should validate the return value of an approved transferFrom call (and other transfer-like methods). For instance, Aragon's Minime token returns false if a call to the transferFrom function fails. This type of vulnerability has been previously encountered in ForceDAO.
Possible mitigation:
Nexus Mutual locks tokens via the tokenInstance.lockForMemberVote() method, which doesn't use transferFrom.
function lockForMemberVote(
    address _of,
    uint _days
) public onlyOperator {
    if (_days.add(now) > isLockedForMV[_of])
        isLockedForMV[_of] = _days.add(now);
}
Snowball Finance and Spirit Swap use similar escrow contracts to lock tokens for a certain period. Both check the result of transfers.
assert ERC20(self.token).transferFrom(_addr, self, _value)
...
assert ERC20(self.token).transfer(msg.sender, value)

Attack #5: Short Voting Window

Users and veto-holders who oppose certain proposals may not have enough time to react, especially if the quorum is less than 50%.
Possible mitigation:
In Aragon, a vote and its execution are open for a voteTime.
function _isVoteOpen(Vote storage vote_) internal view returns (bool) {
    return getTimestamp64() < vote_.startDate.add(voteTime) && !vote_.executed;
}
This is a global parameter that is initialized once, so the possibilities of social engineering depend on the initialization of a particular project.

In X-DAO, a vote and its execution are open for 3 days.
uint32 public constant VOTING_DURATION = 3 days;
...
require(
    _timestamp + VOTING_DURATION >= block.timestamp,
    "DAO: voting is over."
);
This should provide sufficient time for active DAO participants to vote.
Snowball Finance has variable but limited time periods that can be set by the governance:
  • The voting period varies from 1 day to 30 days.
  • The execution delay varies from 30 seconds to 30 days.
  • The expiration period is 14 days.
This should provide sufficient time for active DAO participants to vote.
Keep3r Network has variable but limited time periods that can be set by the governance:
  • The voting period varies from 1 day to 30 days.
  • The execution period is 14 days.
This should provide sufficient time for active DAO participants to vote.
In conclusion, while short voting windows can pose a risk in DAOs, many have implemented mechanisms to handle these scenarios correctly, thereby mitigating potential attacks.

Attack #6: Double Voting

A potential vulnerability in DAOs can occur if a hacker is able to vote twice for a proposal using the same tokens. Here are some scenarios to consider:
  • Vote, transfer tokens, then vote again.
  • Vote, delegate tokens, then vote again.
  • Manipulate the vote() arguments to add extra voting power.
  • Check for reentrancy.
Possible mitigation:
In Aragon, tokens can be transferred between users, but only the block prior to a proposal creation is considered, preventing double voting. There is no delegation mechanism in default Aragon contracts, and there's nothing to manipulate in the vote() function. The code follows a check-effect-interaction pattern, making it invulnerable to reentrancy.

In X-DAO, it's possible to sign a vote, transfer tokens to another account, and sign another vote. However, the execute() method only counts the final token distribution, making double voting inapplicable. There is no delegation mechanism and no on-chain vote() method, so there's nothing to manipulate or try to re-enter.

In Spirit Swap, voting can only change token weights in the protocol, and it applies changes in the same method which the user votes by. It's possible to vote, wait until the tokens are unlocked in the escrow contract, transfer the tokens to another account, lock them again, and vote for the same proposal. However, calculations show that the total voting power applied would be the same if the tokens were simply locked for the entire time. There's no benefit. A user's voting power locked in the escrow contract cannot be delegated to another user. The vote() method takes into account all its arguments correctly, and passing the same tokens in an array does not affect the calculation correctness since all weights are divided by the total weight sum passed in the array. There is an external call in the vote() method, but the IBribe contracts can be considered trusted, so even though there may be a vulnerability here, it does not pose a threat.

Attack #7: Double Execution

Is there a reentrancy in the execute() method? Can it be called twice in the same block?
Possible mitigation:
Aragon, X-DAO, and Keep3r Network use the check-effect-interaction pattern, so their execution methods are not vulnerable to reentrancy.
Snowball Finance implements the nonReentrant modifier and its execution method is also not vulnerable to reentrancy.
Spirit Swap has no execute() method: it applies changes in the vote() method.

Attack #8. Potential Vulnerability in Proposal Creation Process

Let's examine Optimism Governance security analysis. One of the finding was "Potential Vulnerability in Proposal Creation Process".

When a new proposal is initiated through the OptimismGovernorV5.sol contract, the proposer has two options:
  1. propose(): This follows the standard governor proposal process, which necessitates that the quorum is met (yes votes + abstain votes >= quorum) and the vote is successful (yes votes > no votes).
  2. proposeWithModule(): This method calls out to the specified module with proposer-defined parameters that are necessary for the proposal to pass. It allows for certain "options" to pass while others fail. It requires these parameters to be met, as well as the quorum to be met (yes votes + abstain votes >= quorum).

The issue arises with the use of proposeWithModule(), which effectively lowers the minimum parameters for passing proposals because it does not account for no votes and substitutes that with proposer-defined logic.

The only strict requirement for a proposal to proceed is for the quorum to be met. Beyond that, decisions are delegated to the logic passed to the module.
Given that this logic is defined by the proposer, they can configure it in a way that makes the proposal pass more easily than it should, enabling a small minority of the community to pass proposals that the majority of the community does not support.
Possible mitigation:
Ensure that the requirements to pass a proposal through the module are always greater than or equal to the normal proposal process.
In this case, that means ensuring there is the ability to vote no on the proposal as a whole, and that the whole proposal will fail if yes votes <= no votes.

Attack #9. No way to access ETH provided by non-member votes in RocketDAO

The DAO members can initiate node challenges free of charge as a way to verify their activeness. Non-DAO members, however, must pay a members.challenge.cost equal to 1 ETH to launch a challenge. The issue arises when the challenge cost gets trapped within the contract instead of being redirected or used as system collateral.
Possible mitigation:
During the challenge process, the ETH should be locked inside the contract. In cases where a challenge is refuted, the locked value could be utilized as protocol collateral. Conversely, if the challenge proves successful and the node is removed, the challenger should ideally be refunded the amount they had to initially lock up.

Attack #10. A malicious user could DOS a vesting schedule by sending only 1 wei ofTLCto the vesting escrow in Liquid Collective

An external user possessing TLC tokens can potentially disrupt any user's vesting schedule by merely sending 1 wei of TLC to the escrow address associated with the vesting schedule. This action could result in:
  • The vesting schedule's creator being unable to revoke the vesting schedule.
  • The vesting schedule's beneficiary being unable to release any vested tokens until the vesting schedule ends.
  • Any external contracts or decentralized applications (dApps) being unable to call computeVestingReleasableAmount.
All functions internally invoking _computeVestingReleasableAmount will throw an underflow error and revert if called before the end of the vesting schedule.
The underflow error occurs because if _computeVestingReleasableAmount is called before the schedule ends, it enters the _time < _vestingSchedule.end condition and tries to compute uint256 releasedAmount = _computeVestedAmount(_vestingSchedule, _vestingSchedule.end) - balanceOf(_escrow);. Here, _computeVestedAmount(_vestingSchedule, _vestingSchedule.end) is always less than balanceOf(_escrow), resulting in an underflow error and reversion of the contract.
However, once the vesting period concludes, the contract will not enter the _time < _vestingSchedule.end condition, and the user will be able to obtain the entire vested amount, plus any extra TLC transferred to the escrow account by the malicious user.
Possible mitigation:
Reconsider the implementation of how the contract accounts for the amount of released tokens in a vesting schedule to prevent this scenario. If the new implementation no longer relies on balanceOf(_escrow), remember that tokens sent directly to the escrow account would be permanently stuck.

DAO smart contract audit importance

Smart contract audits stand as an essential protective measure, capable of uncovering potential weak points within the DAO code that may be exploited, leading to reputation tarnishing or loss of assets. Moreover, blockchain audits amplify system efficiency and performance by spotting and correcting faults and refining the underlying code.

Read more: Data availability in web3

The Remedy – Undertaking a DAO Smart Contract Audit

During the smart contract auditing procedure, auditors painstakingly examine the code to identify any possible vulnerabilities. These could range from susceptibility to denial of service attacks, gas limit issues, reentrancy attacks, and insecure random number generation, to overflow and underflow errors, and logical inconsistencies. This thorough vulnerability analysis labels each security issue with a severity level. As a result, the concluding audit report serves as a comprehensive guide on the corrective measures needed to boost security.

How Can Participants Mitigate Potential Risks?

Here are some fundamental guidelines for safeguarding your DAO participation and governance:
  1. Choose trustworthy DAO platforms and secure wallets for storage.
  2. Stay vigilant against scams and authenticate the credibility of any proposals before executing transactions involving funds or voting rights.
  3. Enable multi-factor authentication wherever possible.
  4. Review the details of each DAO proposal thoroughly before authorizing it through your wallet.
Looking for support with deployment or smart contract audit?

Check our proprietary service
Deployment Check

We would be happy to discuss any of your security and deployment requests

What Does a DAO Audit Entail?

DAO audit is an exhaustive code review aimed at affirming the technical integrity and safety of a token, smart contract, and DAO platform, hence reducing the potential for cyber threats.

Is an Audit Necessary for DAOs?

Similar to any other token, DAO tokens also necessitate auditing. This is vital to decrease the risk of these digital assets being jeopardized or stolen by cybercriminals.

What is Smart Contract Auditing?

Smart contract auditing is a stringent security protocol in which a qualified external auditor scrutinizes the smart contract code, typically written in languages like Solidity, Move, Vyper, or Rust. This procedure is intended to discover any vulnerabilities that could endanger the system's functioning.