DAO Governance Attacks: How Proposals Get Hijacked
Quick answer. Governance attacks exploit flaws in a DAO's voting or execution logic to pass a malicious proposal, often one that drains the treasury. Common causes: reusable votes, flash-loaned votes cast and executed in one transaction, and unvetted proposal contracts.
DAO and governance attacks are behind some of the largest exploits in DeFi.
A governance contract can move an entire treasury in one transaction, so one flaw in its logic puts every dollar it controls at risk.
This guide covers how DAO voting logic works, the common flaws behind governance attacks, and a full walk-through of the Beanstalk governance exploit.
What Is a DAO?
A DAO is a decentralized autonomous organization. It is a set of smart contracts that decides how a group of entities makes decisions together.
Any organization, from a company to a family, makes decisions. A DAO's contracts simply facilitate that process onchain.
A typical DAO has a pool of funds it governs and a governance contract that tracks votes on proposals. The flow looks like this:
- Propose. Someone creates a proposal to do something with the funds, such as donating to an organization.
- Vote. Any eligible address calls a vote function and votes yes or no.
- Execute. If enough votes back it, the proposal passes and executes. The governance contract can move funds onchain in that same execution transaction.
- Expire. If it does not pass, it is removed or marked inactive, depending on the contract.
Nouns DAO is a well-known example. One Nouns NFT is auctioned each day, and the proceeds go to the DAO's treasury.
At the time of recording (November 2023), one auction stood at a 20 ETH bid, over $30,000. The treasury held almost $9 million.
Holders of a Noun can vote on proposals and direct that treasury.
Where Governance Attacks Focus
The whole focus of a governance attack is the execution of a proposal.
Most of the time, the attacker submits a malicious proposal and finds a way to get it through.
This is the obvious target because one execution can move any amount of funds, even the whole treasury.
Imagine a proposal that sends the entire treasury to its author.
If voting power is decentralized, the author's 10% votes yes and the other 90% votes no, because the proposal gives them nothing.
So review the governance contract for business logic flaws that let a malicious proposal pass and execute anyway.
Common DAO Attack Vectors
1. Voting power that moves after a vote
When a user votes, their voting power must be locked to that proposal and that address. Voting power can be tokens, NFTs or anything else the DAO counts.
If it is not locked, a user can vote, transfer the tokens to a new address and vote again. Repeat that, and one token carries unlimited voting power.
It sounds obvious, but this flaw comes up surprisingly often in governance implementations.
2. Flash-loaned voting power
Make sure no one can flash loan the governance token to push a proposal through. The attack needs two things to be true:
- The attacker can flash loan the governance token and gain voting power over a live proposal in a single transaction.
- The attacker can get the governance token back in that same transaction to repay the loan.
In practice, this usually means the attacker can vote, cross the threshold and execute the proposal all in one transaction.
If voting and execution can happen in the same transaction, treat it as a red flag.
The defense is to separate them. Voting and execution must land in different transactions, even if those sit in the same block.
Then the flash loan cannot be repaid without dropping below the voting threshold.
Depending on the logic, the voter may not even get the tokens back until the proposal ends.
3. Buggy or malicious proposal contracts
This flaw is not in the governance contract itself. A well-written governance contract will still execute whatever the proposal contains.
If the contract behind a proposal is buggy, has a backdoor or is outright malicious, passing it can be just as damaging. The proposal may even be well-meant and simply contain a bug.
So on top of a well-audited governance contract, get reviewers on every contract attached to a new proposal.
Any contract attached to a proposal should also be free of the SELFDESTRUCT opcode.
In the Tornado Cash governance exploit, a hidden self-destruct worked as a backdoor that let the attacker replace the contract's logic after the vote.
EIP-6780, which shipped with Ethereum's Dencun upgrade in March 2024, changes how self-destruct behaves to close most of that path.
The full breakdown is in our guide to metamorphic contracts and the Tornado Cash exploit.
The Beanstalk Governance Exploit
Beanstalk's governance facet was exploited for over $180 million. Walking through how it worked shows several of these flaws in one place.
Beanstalk is built on the Diamond proxy standard. For background on diamonds, see upgradeable smart contracts explained.
Proposing
The propose function creates a Beanstalk Improvement Proposal (BIP), stores it with its time window, and counts the proposer as the first voter. You propose it, and you vote for it yourself.
Voting
Other holders call vote to back a proposal. It records the vote and places a "voted until" marker.
Recording the vote marks the account as having voted on that BIP, which stops anyone voting twice. That is another baseline check every governance contract needs.
The contract then tracks how much voting power, counted in Beanstalk's "roots", backs the proposal. If that crosses the threshold, the proposal can pass.
Committing
The commit function executes a passed proposal. It checks that the BIP is valid and that its vote percentage meets the governance pass threshold.
That threshold is exactly 50%. With 1e18 representing 100%, the constant is 5e17.
Execution then marks the BIP as ended and executed, runs the proposal's diamond cut, updates the paused state and rewards the caller.
The reward exists so that someone always has a reason to execute passed proposals.
The diamond cut
If the proposal includes a diamond cut, execution calls LibDiamond.diamondCut. That function adds, replaces or removes facets for given function selectors.
More importantly, at the end it always calls initializeDiamondCut, even if there are no facet changes. That function delegatecalls the proposal's init address with the proposal's calldata.
That is an arbitrary address running arbitrary code with arbitrary calldata. And it runs by delegatecall from the diamond, which holds all of the protocol's storage and funds.
So a passed proposal can do literally anything to the protocol.
This is why proposals must be vetted and voted on, and why a proposal must never be proposed and executed at once.
Why Normal Commits Were Safe
The regular commit path is protected by one requirement: the proposal must not be active.
A proposal is active while the current season, Beanstalk's unit of time, is still within the proposal's end.
Voting requires the proposal to be active, and committing requires it to be inactive.
So a vote and a commit can never happen in the same transaction. Nobody can flash loan governance tokens, vote, execute and repay in one go.
Here is a simplified sketch of the pattern. It is not Beanstalk's source, only the shape of the checks.
function vote(uint32 bip) external {
require(isActive(bip), "voting closed");
// record the vote and add the voter's power
}
function commit(uint32 bip) external {
require(!isActive(bip), "voting still open");
require(votePercent(bip) >= PASS_THRESHOLD, "no majority");
_execute(bip); // delegatecalls the proposal's init address
}
function emergencyCommit(uint32 bip) external {
require(isActive(bip), "voting closed"); // the flaw: voting is still open
require(block.timestamp >= startTime(bip) + EMERGENCY_PERIOD, "too early");
require(votePercent(bip) >= SUPER_MAJORITY, "no super majority");
_execute(bip);
}
The Emergency Commit Flaw
Beanstalk also had an emergencyCommit function, meant for urgent proposals that could not wait for the normal voting period.
Its key requirement was the opposite one: the proposal must still be active.
After an emergency period of one day, a proposal could be emergency committed while voting was still open.
That puts voting and execution in the same transaction, which is exactly the flash loan setup described above.
The emergency threshold was higher than 50%: two-thirds, or about 66.7%. With hundreds of millions of dollars in flash loans available, that was not hard to reach.
To gain voting power, an attacker could flash loan tokens, provide liquidity on Curve and deposit the LP tokens into Beanstalk's Silo. That deposit grants governance power.
How the attack played out
- The attacker proposed a BIP whose init address pointed to a malicious contract. When delegatecalled, it sent the diamond's funds, such as its ETH and USDC, to the attacker.
- They waited one day for the emergency period to pass.
- In a single transaction, they borrowed from several flash loan providers, gained voting power through Curve and the Silo, and voted for their own proposal.
- That put them over the two-thirds super majority, so they called
emergencyCommit. - The delegatecall ran their contract inside the diamond and sent the funds to them, and they repaid the loans. They drained over $180 million from the protocol.
Governance Review Checklist
- Voting power is locked to the proposal and the address that used it.
- No address can vote twice on the same proposal.
- Voting and execution can never happen in the same transaction, including on emergency or fast-track paths.
- No threshold can be reached with flash-loaned tokens that are repaid in the same transaction.
- You know exactly what execution can call. A delegatecall to a proposal-supplied address can do anything.
- Every contract attached to a proposal is reviewed and well understood before the vote.
- No proposal contract contains
SELFDESTRUCT.
For more patterns like these, see our list of common smart contract vulnerabilities.
How Guardian Helps
A Guardian smart contract audit starts with a design review of governance, roles and upgrade paths, before implementation locks in the expensive risks.
Senior researchers then attack privileged flows and protocol logic with proof-of-concept depth.
Vanguard puts two independent teams on the same codebase, and Guardian keeps reviewing updates to the audited scope for six months after production.
Frequently Asked Questions
What is a governance attack?
A governance attack exploits a DAO's voting or execution logic to pass a proposal most holders would reject, such as one sending the treasury to the attacker. It targets execution, which can move every fund the DAO controls.
How do flash loans enable governance attacks?
If an attacker can borrow governance tokens, vote, execute and get the tokens back in one transaction, they repay the loan and keep the proceeds. Forcing voting and execution into separate transactions blocks this.
How was Beanstalk's governance exploited?
Normal commits required voting to be closed, but the emergency commit required it to be open. So in one transaction, the attacker flash-loaned voting power, passed the two-thirds threshold and executed a proposal that sent them the funds.
Why should proposal contracts be audited?
A flawless governance contract still executes whatever a proposal contains. If the proposal's contract is buggy, backdoored or contains SELFDESTRUCT, passing it can hand control to an attacker.
Sources
Get your governance contracts reviewed by Guardian
Guardian reviews governance logic, proposal execution and upgrade paths before they hold real funds.