Skip to content
Quantix Security Labs
Technical analysis

Governance attacks in DeFi

On-chain governance turns token balances into authority over code and treasuries. How that authority has been borrowed, bought, hidden in proposal payloads and routed around timelocks.

Written by
Quantix Research, DeFi Security
Published
Reading time
6 minutes
Category
DeFi Security

Technical analysis. Built from the public sources in the bibliography. Incident details are as reported there; no new discovery is claimed.

Illustration: an electorate arranged around a proposal, with one column of borrowed voting power from a lending pool and a gap in the timelock ring.
Contents
  1. Tokens as authority
  2. The lifecycle of a proposal
  3. Borrowed voting power
  4. Payloads that are not what they seem
  5. Cheap quorums and timing
  6. Paths around the timelock
  7. Patterns and incidents
  8. Defences that change the economics
  9. Conclusions
  10. Recommendations
  11. Bibliography

On-chain governance gives token holders direct authority over a protocol: they can upgrade contracts, change parameters, list collateral and move treasury funds. That authority is only as legitimate as the process that exercises it. If voting power can be borrowed, if a proposal’s effect can differ from its description, or if a privileged path can skip the process, the protocol is governed by whoever exploits the gap.

This analysis maps the governance lifecycle, places the known attack patterns on it, and examines two well-documented public incidents in detail. The descriptions of those incidents summarise the published analyses listed in the bibliography.

Tokens as authority

Governance tokens convert economic stake into control. The design assumption is that holders with a long-term stake will act in the protocol’s interest, and that acquiring enough stake to cause harm would cost more than the harm is worth. Both assumptions can fail. Stake can be held briefly, through flash loans or borrowing, and the value controlled by governance, such as a treasury or the assets behind an upgradeable contract, can far exceed the cost of a winning vote.

The lifecycle of a proposal

On-chain governance lifecycle and its attack pointsSix stages: propose, voting delay, vote, queue, timelock delay, execute. Attack points: A at proposal, where a payload can differ from its description; B and C at the vote, where voting power can be borrowed or bought and low turnout makes quorum cheap; D at the timelock delay, if it is too short to review or exit; E at execution, where an emergency path or privileged executor skips the delay.ProposeVoting delayVoteQueueTimelock delayExecuteABCDEVoting power should be read from a past checkpoint, so tokens acquired after the snapshot do not count.APayload differs from its description, or can change after approvalBVoting power borrowed or bought: snapshot taken at the wrong timeCLow turnout: quorum reachable with a small, concentrated stakeDDelay too short for holders to review the payload or exitEEmergency path or privileged executor that skips the delay
A typical on-chain governance lifecycle. Lettered points mark where the patterns described below apply.

A proposal is created with a list of actions, waits through a voting delay, is voted on during a voting period, and, if it passes, is queued in a timelock and executed after a delay. Each stage has a purpose: the delay lets voters prepare, the snapshot fixes who may vote, the timelock lets users review the outcome and exit before it takes effect. Attacks target stages whose purpose is not actually enforced.

Borrowed voting power

If voting weight is read at the moment of voting, anyone who can borrow tokens for the duration of one transaction can vote with them.

Governance.sol (illustrative, vulnerable)solidity
// Simplified, illustrative governance module. Not production code.function castVote(uint256 proposalId, bool support) external {    Proposal storage p = proposals[proposalId];    require(block.number <= p.endBlock, "closed");    uint256 weight = token.balanceOf(msg.sender);     // current balance: can be borrowed for one tx    require(!hasVoted[proposalId][msg.sender], "voted");    hasVoted[proposalId][msg.sender] = true;    if (support) p.forVotes += weight; else p.againstVotes += weight;}

Beanstalk (April 2022). Immunefi’s analysis describes how an attacker used flash loans from several lending and exchange protocols to acquire assets, deposited them into Beanstalk to obtain a supermajority of voting power, and called emergencyCommit, a function that executed a proposal immediately once it had a supermajority, provided a day had passed since the proposal was created. The attacker had submitted the proposals the day before. One of them transferred the protocol’s assets to the attacker. Because voting and execution happened in the same transaction, the flash loans were repaid within it.

The underlying defect was not the flash loan but the absence of any delay between voting and execution, combined with voting power that reflected the current state rather than a past snapshot. Reading voting power from a checkpoint taken before the vote, as tokens implementing ERC-5805 allow through getPastVotes, removes the flash-loan route entirely.

Payloads that are not what they seem

Voters approve a description; the chain executes calldata. The two can differ in three ways: the calldata does something other than the description says, the calldata calls a contract whose behaviour is not obvious from the proposal, or the contract called can change between approval and execution.

Tornado Cash governance (May 2023). Halborn’s write-up describes a proposal that claimed to repeat the logic of an earlier, legitimate proposal, but whose contract included hidden logic allowing it to self-destruct so that different code could later be deployed at the same address. After the proposal passed, the attacker replaced the code. When governance executed the proposal by delegatecall, the new code assigned 10,000 votes to each of many attacker-controlled addresses, giving the attacker about 1.2 million votes against roughly 70,000 legitimate ones and control of governance.

Since the Cancun upgrade, EIP-6780 limits SELFDESTRUCT on Ethereum so that it removes code only when called in the same transaction that created the contract, which closes this particular technique there. The general lesson remains: a proposal should be judged by the code that will actually run at execution, including any upgradeable contract it calls, and governance executors that use delegatecall give that code the governor’s full authority.

Cheap quorums and timing

Quorums are usually a fraction of total supply. When turnout is low, a proposal can reach quorum with a small, concentrated stake, and a proposal timed for a holiday or published with little notice may pass before most holders notice. Voting delays that are too short reduce the time available to organise opposition. The systematisation of attacks on DAOs by Feichtinger et al. finds that many attacks exploit such governance and human factors rather than code flaws, which audits focused on code are poorly placed to catch.

Paths around the timelock

A timelock protects users only if every privileged action passes through it. Emergency functions, guardian roles, admin keys retained after launch and executors with broad permissions are all paths around it. Beanstalk’s emergencyCommit was one such path. Others are less obvious: a timelock whose admin role was never renounced, a proposer role granted to an externally owned account, or a contract that the governor can upgrade without a delay. The governance timelock bypass case study traces such a path in a protocol from Quantix Protocol Research.

ProtocolGovernor.sol (illustrative)solidity
// Illustrative OpenZeppelin Governor configuration (required overrides omitted).contract ProtocolGovernor is    Governor, GovernorSettings, GovernorCountingSimple,    GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockControl{    constructor(IVotes token, TimelockController timelock)        Governor("ProtocolGovernor")        GovernorSettings(            7_200,      // voting delay: about 1 day in blocks before the snapshot            50_400,     // voting period: about 1 week in blocks            100_000e18  // tokens needed to create a proposal        )        GovernorVotes(token)                // weight = getPastVotes(account, snapshot)        GovernorVotesQuorumFraction(4)      // quorum = 4% of past total supply        GovernorTimelockControl(timelock)   // every action executes through the timelock    {}}

In this configuration, voting weight is read at a snapshot taken after the voting delay, so tokens acquired later do not count; quorum is computed from past total supply; and execution can happen only through the timelock. The timelock itself must be configured so that the governor is its only proposer and no other account holds its admin role.

Patterns and incidents

PatternStagePublic examplePrimary control
Borrowed voting powerVoteBeanstalk, April 2022Past-checkpoint voting weight; delay before execution
Immediate execution pathExecuteBeanstalk, April 2022All execution through a timelock
Payload replaced after approvalPropose to executeTornado Cash governance, May 2023Immutable, verified payloads; fork simulation
Low-turnout captureVoteDiscussed in the DAO attacks literatureAdequate quorum and voting period; delegation
Retained admin or guardian powersExecuteDiscussed in the DAO attacks literatureRenounce or narrowly scope roles; monitoring
Governance attack patterns, the stage they target and a public incident where one is documented in the bibliography

Defences that change the economics

Most governance defences work by raising the cost of an attack or by giving honest participants time to respond. Checkpointed voting power makes stake expensive to acquire for an attack, because it must be held before the snapshot. Voting delays and periods give holders time to notice. Timelocks give users time to exit, which caps what a hostile proposal can take from anyone paying attention. Narrowly scoped guardians, able to cancel queued proposals but not to execute arbitrary actions, add a check without adding a bypass. Finally, limits on what governance can do in one proposal, such as caps on treasury transfers, bound the damage of any single success.

Conclusions

Governance attacks succeed where the lifecycle’s safeguards exist on paper but not in code: voting weight read in the present, execution that skips the delay, payloads that can change or hide their effect, and privileged paths that bypass the timelock. The two incidents examined here exploited exactly those gaps.

Sound governance is mostly configuration: checkpointed votes, adequate delays, a timelock with no side doors, and a discipline of judging every proposal by the code that will execute.

Recommendations

Protocol teams

  1. Read voting power from past checkpoints (ERC-5805) and route every privileged action through a timelock.
  2. Remove or narrowly scope emergency powers; a guardian should be able to cancel, not to execute.
  3. Publish a fork simulation of every proposal’s execution, with the resulting state changes.

Delegates and voters

  1. Vote on calldata and its simulated effect, not on the description alone.
  2. Treat calls to upgradeable or unverified contracts in a proposal as unreviewed code.

Reviewers

  1. Enumerate every path that can change protocol state with privileged authority, and confirm each passes through the timelock.
  2. Check timelock roles: proposer, executor, canceller and admin.

Bibliography

Primary sources: standards, official documentation, incident reports and papers.

  1. 1Governance(opens in a new tab)OpenZeppelin Contracts 5.x documentation
  2. 2ERC-5805: Voting with delegation(opens in a new tab)Ethereum Improvement Proposals
  3. 3EIP-6780: SELFDESTRUCT only in same transaction(opens in a new tab)Ethereum Improvement Proposals
  4. 4Hack Analysis: Beanstalk Governance Attack, April 2022(opens in a new tab)Immunefi
  5. 5Explained: The Tornado Cash Hack (May 2023)(opens in a new tab)Halborn
  6. 6SoK: Attacks on DAOs(opens in a new tab)Feichtinger et al., arXiv:2406.15071

Applied on this site

Assessments, case studies and tools that apply this publication.

Want this question asked of your code?

Quantix reviewers apply the same reasoning to production systems. Share what you are building and when it ships.