GOVERNANCE ATTACK

BEANSTALK FARMS
$182M EXPLOIT

Flash loan. Instant supermajority. Emergency execution. Democracy weaponized.

LOSS
$182,000,000
STATUS
VERIFIED
VECTOR
GOVERNANCE
DATE
APR 17, 2022

The Perfect Storm

One billion dollars. One transaction. One block.

On April 17, 2022, an attacker flash loaned $1 billion in stablecoins from Aave, converted them to Curve LP tokens, and deposited them into Beanstalk's Silo—the protocol's staking mechanism that grants voting power.

The Silo granted voting power immediately upon deposit. No vesting. No snapshot. The attacker now held 79% of all Stalk (voting power)—a supermajority that enabled them to execute any proposal instantly via emergencyCommit().

They drained $182M before the flash loan even needed to be repaid.

// The Vulnerability

Code Anatomy

The emergencyCommit() function checks voting power at the moment of execution—not from a historical snapshot. Flash loans exploit this by acquiring temporary supermajority within a single transaction.

GovernanceFacet.sol — VULNERABLE
1function emergencyCommit(uint32 bip) external {
2 // Get the proposer of this BIP
3 address bipProposer = bip.proposer;
4
5 // Check proposal meets emergency threshold
6 // BUG: Uses CURRENT voting power, not snapshot!
7 require(
8 balanceOfStalk(msg.sender) >=
9 totalStalk().mul(C.EMERGENCY_THRESHOLD).div(100),
10 "Governance: Must have >= 67% voting power"
11 );
12
13 // If threshold met, execute IMMEDIATELY
14 // No timelock, no delay, no cooldown period
15 _execute(bip);
16
17 // THE FLAW: Flash loans can acquire Stalk instantly
18 // by depositing into the Silo, then immediately
19 // call emergencyCommit() with supermajority power
20 // and execute ANY arbitrary code via a malicious BIP
21}
NO SNAPSHOT CHECK

Fig. 2: The emergencyCommit() function — uses live voting power instead of snapshot

Governance Design Comparison

FeatureBeanstalkSafe Design
Voting Power SourceCurrent balanceSnapshot at proposal
Emergency Threshold67% (supermajority)67% + timelock
Execution DelayNone (instant)24-48h minimum
Flash Loan DefenseNoneBlock-based snapshots
Vesting RequiredNoYes (epochs)
// Proof of Concept

Live Exploit Reproduction

Watch the vulnerability come to life. This PoC runs against a mainnet fork at the exact block before the exploit (14602789). We demonstrate acquiring 43% voting power with $180M—the real attacker used $1B for 79%.

beanstalk_exploit_poc.sh — Block 14602789 (Mainnet Fork)

Fig. 1: Live reproduction of the exploit on Ethereum Mainnet Fork (Block 14602789)

// Attack Vector

The Six-Step Takeover

STEP 1

Flash Loan

Borrow $1B (DAI + USDC + USDT) from Aave V2

STEP 2

LP Conversion

Convert stables to Curve 3CRV, then BEAN3CRV-f LP tokens

STEP 3

Silo Deposit

Deposit LP into Beanstalk Silo — receive instant Stalk (voting power)

STEP 4

THE EXPLOIT

Call emergencyCommit(BIP-18) — now holding 79% Stalk supermajority

STEP 5

Execute BIP

Malicious proposal drains all protocol funds to attacker's contract

STEP 6

Repay & Profit

Repay flash loan, launder $76M profit through Tornado Cash

Verified on Real Data

Fork Block
14602789
Voting Power
43% (w/ $180M)
PoC Execution
PASSED

Analysis by 0xWalterWhiteHat

Request an Audit