Beanstalk Farms Hack
The Story
On April 17, 2022, Beanstalk Farms, an Ethereum-based stablecoin protocol, fell victim to a sophisticated governance attack that resulted in the loss of approximately $182 million. Unlike many hacks that exploit code vulnerabilities, this attack leveraged the protocol's governance mechanism and flash loans to gain control of the project.
The attacker borrowed a massive amount of crypto assets through flash loans, temporarily giving themselves enough voting power to pass malicious governance proposals. Within minutes, they executed their attack, draining the protocol's funds, and making off with about $76 million in profit after repaying the flash loans.
The incident highlighted critical vulnerabilities in on-chain governance systems, particularly those that don't implement time delays for proposal execution or have safeguards against flash loan attacks. Beanstalk later relaunched with a redesigned governance system and has been working to gradually compensate affected users.
Technical Analysis
The Beanstalk hack was a governance attack that exploited the protocol's on-chain voting system. Here's how it was executed:
- The attacker created a malicious governance proposal (BIP-18) that would drain all protocol funds to their address, disguised as a donation to Ukraine
- They took out a flash loan of nearly $1 billion in assets (approximately $900M in various cryptocurrencies)
- Using these borrowed assets, they acquired enough governance tokens to gain a 67% voting majority
- They executed their proposal, which passed immediately due to Beanstalk's governance design
- The protocol's funds were drained to the attacker's wallet
- They repaid the flash loan and kept about $76 million in profits
The vulnerability was in Beanstalk's governance mechanism, which allowed:
- Immediate execution of proposals without time delay
- Voting power directly proportional to token holdings, even if recently acquired
- No protection against flash loan governance attacks
// Simplified representation of the vulnerable governance code
function executeProposal(uint256 proposalId) public {
Proposal storage proposal = proposals[proposalId];
// Check if proposal has enough votes (67% majority)
require(
proposal.forVotes > (totalVotes * 2) / 3,
"Proposal doesn't have enough votes"
);
// Execute proposal immediately without time delay
(bool success, ) = proposal.target.call(proposal.data);
require(success, "Proposal execution failed");
emit ProposalExecuted(proposalId);
}
Lessons Learned
- Governance systems should implement mandatory time delays between proposal approval and execution
- Voting power should be based on tokens held over time (time-weighted) rather than instantaneous snapshots
- Flash loan protection mechanisms are crucial for DeFi protocols with on-chain governance
- Emergency pause mechanisms should be implemented to prevent rapid exploitation
- Multi-signature controls for critical functions can add an additional layer of security