We do not have a reliable USD price for the recorded assets yet.
0xcd314668aaa9bbfebaf1a0bd2b6553d01dd58899c508d4729fa7311dc5d33ad70xc1e088fc1323b20bcbee9bd1b9fc9546db5624c5EthereumAn unprivileged adversary used a flash-loan-amplified governance attack against the Beanstalk protocol’s diamond contract (0xc1e088fc1323b20bcbee9bd1b9fc9546db5624c5) on Ethereum mainnet. By temporarily amassing a large Bean and Bean-ETH LP position and depositing it into the Beanstalk Silo, the attacker minted an overwhelming amount of governance roots in a single transaction. Because Beanstalk governance counted live Silo roots without a proposal-time snapshot or time-weighting, the attacker could immediately vote for their own malicious proposal (BIP‑18) and call emergencyCommit(18) in the same transaction. The BIP‑18 diamond cut then executed an init delegatecall that transferred the Beanstalk treasury’s entire Bean and Bean‑ETH Uniswap V2 LP balances to an attacker-controlled helper contract. After unwinding flash loans and swaps, the attacker’s EOA realized a large net profit in ETH terms while the protocol’s Bean and LP treasury was effectively drained.
Beanstalk is implemented as a diamond proxy whose facets share a common AppStorage layout, with governance and Silo state stored in dedicated structs. The Silo tracks per-account Bean and Bean‑ETH LP deposits, deriving two key quantities: stalk (a measure of yield-bearing stake) and roots (the unit of governance voting power). Governance BIPs are created and managed via GovernanceFacet functions dispatched through the diamond’s fallback.
When a user deposits Bean or Bean‑ETH LP into the Silo via SiloFacet::depositBeans or SiloFacet::depositLP, the call flows through helper contracts (, ) that compute how much stalk and roots to mint. Importantly, immediately updates:
BeanSiloLibSiloLibSiloincrementBipRoots in AppStorage.Governance.There is no snapshot of voting power at proposal time and no requirement that Silo deposits remain in place beyond the current transaction. Governance thresholds (quorum and supermajority) are evaluated against the current roots recorded in storage whenever GovernanceFacet::vote or GovernanceFacet::emergencyCommit is called.
Beanstalk’s treasury reserves (including Bean and Bean‑ETH LP) are held directly in the diamond contract. Governance BIPs can modify the diamond by installing new facets and running an init delegatecall. In BIP‑18, the attacker deployed a malicious init contract that, when executed, read the Beanstalk treasury’s Bean and Bean‑ETH LP balances and transferred them to an attacker-controlled helper contract.
All of the above components—Silo deposits, governance calls, flash loans, AMM and Curve interactions—are publicly accessible on Ethereum mainnet. Any EOA can call the same interfaces under standard gas limits, and the attacker’s strategy does not rely on privileged keys or whitelisted roles, making this an ACT (anyone-can-take) opportunity.
The core vulnerability is a governance design flaw: Beanstalk governance derives voting power from live Silo roots without a proposal-time snapshot, time-weighting, or requirement for economically committed stake. Silo deposits can be created and removed within a single transaction, yet their associated roots are immediately counted toward BIP thresholds.
In the exploit, the attacker used flash loans and public DeFi routes to temporarily acquire a large Bean and Bean‑ETH LP position, deposited these assets into the Silo via SiloFacet, and thereby minted an overwhelming amount of roots for their helper contract. LibSilo::incrementBalanceOfStalk and incrementBipRoots immediately updated both the account’s roots and BIP‑18’s roots tally in governance storage. The attacker then invoked GovernanceFacet::vote and GovernanceFacet::emergencyCommit(18) in the same transaction, causing the diamond to execute a malicious BIP‑18 init that drained the Bean and Bean‑ETH LP treasury to an attacker-controlled address. After unwinding the flash loans, the adversary’s EOA realized a large ETH-denominated profit.
The invariant that governance power should reflect durable, economically committed stake was thus violated: transient, flash‑loan‑boosted deposits were sufficient to control Beanstalk’s treasury in a single block.
The relevant governance safety invariant can be stated as:
O(σ_B, σ') = 1 if and only if Beanstalk governance decisions
(including emergencyCommit of BIPs) cannot be passed and executed
solely by same-transaction flash-loan-boosted Silo deposits that
are unwound immediately after execution; governance power must be
tied to economically committed stake measured in a time-consistent way.
In the observed exploit, this invariant is broken. The system permits an account to:
The concrete breakpoint lies in the Silo implementation and its interaction with governance. From the collected Beanstalk source (verified clone under:
artifacts/root_cause/data_collector/iter_2/contract/1/0xc1e088fc1323b20bcbee9bd1b9fc9546db5624c5/source
and
artifacts/root_cause/data_collector/iter_2/contract/1/0x448d330affa0ad31264c2e6a7b5d2bf579608065/source),
the relevant flow is:
// Simplified from SiloFacet/BeanSilo/LibSilo and AppStorage.Governance
function depositBeans(uint256 amount) external {
// ... transfer Bean into the diamond ...
LibSilo.deposit(msg.sender, amount, BEAN_TOKEN);
}
library LibSilo {
function deposit(address account, uint256 amount, address token) internal {
// compute stalk and roots for this deposit
// update per-account balances
incrementBalanceOfStalk(account, stalkDelta);
incrementBalanceOfRoots(account, rootsDelta);
// if there is an active BIP, update its roots as well
incrementBipRoots(account, rootsDelta);
}
}
incrementBipRoots writes into AppStorage.Governance and immediately increases the recorded roots for any in-progress proposal that the depositor has voted on. There is no check that the deposit persists beyond the current transaction, and governance logic later reads these updated roots when evaluating thresholds.
On the governance side, the collected GovernanceFacet sources show that:
propose creates a BIP, sets its parameters, and records an initial vote and roots for the proposer based on current Silo roots; andvote and emergencyCommit check quorum and supermajority thresholds using the current roots stored in AppStorage.Governance.There is no owner/admin gating or privileged whitelist for these functions: any EOA with sufficient roots can call them via the diamond fallback.
The attacker first established a baseline Silo position to participate in governance:
0xf5a698984485d01e09744e8d7b8ca15cd29aa430a0137349c8c9e19e60c0bb9d (block 14595189) is an adversary-crafted deposit from EOA 0x1c5dcdd006ea78a7e4783f9e6021c32935a10fb4 into the Beanstalk Silo.artifacts/root_cause/data_collector/iter_2/tx/1/0xf5a69898.../trace.cast.log) shows calls into SiloFacet and LibSilo, establishing initial stalk and roots for 0x1c5d....Next, the attacker created and configured BIP‑18:
0x68cdec0ac76454c3b0f7af0b8a3895db00adf6daaf3b50a99716858c4fa54c6f (block 14595906) is a GovernanceFacet::propose call from 0x1c5d... routed via the diamond’s fallback.artifacts/root_cause/seed/1/0x68cdec0a.../metadata.json, .../balance_diff.json, .../trace.cast.log, and artifacts/root_cause/data_collector/iter_1/tx/1/0x68cdec0a.../receipt.json) show the creation of BIP‑18, initial parameterization, and recording of an initial vote and roots for 0x1c5d... in AppStorage.Governance.By block 14602790 (pre‑state σ_B), Beanstalk’s treasury holds substantial Bean and Bean‑ETH LP balances in the diamond, and BIP‑18 is configured to execute a diamond cut with a malicious init delegatecall.
The main exploit transaction is:
{
"chainid": 1,
"txhash": "0xcd314668aaa9bbfebaf1a0bd2b6553d01dd58899c508d4729fa7311dc5d33ad7"
}
It is a contract-creation transaction from EOA 0x1c5d... that deploys attacker contract 0x728ad672409da288ca5b9aa85d1a55b803ba97d7 and then executes a complex sequence of calls in a single trace:
// Seed profit transaction evidence snippet (balance_diff.json)
{
"chainid": 1,
"txhash": "0xcd314668aaa9bbfebaf1a0bd2b6553d01dd58899c508d4729fa7311dc5d33ad7",
"native_balance_deltas": [
{
"address": "0x1c5dcdd006ea78a7e4783f9e6021c32935a10fb4",
"before_wei": "27390250384248195067",
"after_wei": "24857169237510444597435",
"delta_wei": "24829778987126196402368"
}
],
"erc20_balance_deltas": [
{
"token": "0xdc59ac4fefa32293a95889dc396682858d52e5db",
"holder": "0xc1e088fc1323b20bcbee9bd1b9fc9546db5624c5",
"before": "36084584376516",
"after": "0",
"delta": "-36084584376516",
"contract_name": "Bean"
},
{
"token": "0x87898263b6c5babe34b4ec53f22d98430b91e371",
"holder": "0xc1e088fc1323b20bcbee9bd1b9fc9546db5624c5",
"before": "540716100968756904",
"after": "0",
"delta": "-540716100968756904",
"contract_name": "UniswapV2Pair"
},
{
"token": "0xdc59ac4fefa32293a95889dc396682858d52e5db",
"holder": "0x79224bc0bf70ec34f0ef56ed8251619499a59def",
"before": "0",
"after": "36398226924163",
"delta": "36398226924163",
"contract_name": "Bean"
}
]
}
The trace (artifacts/root_cause/seed/1/0xcd31466.../trace.cast.log) and related artifacts show the following steps:
0x728a... takes flash loans and uses Curve and AMM pools (including Bean/LUSD pool 0xd652c40fbb3f06d6b58cb9aa9cff063ee63d465d and other DeFi components) to convert borrowed assets into large Bean and Bean‑ETH LP positions.0x79224bc0bf70ec34f0ef56ed8251619499a59def, which then calls Beanstalk’s SiloFacet::depositBeans and depositLP via the diamond fallback. LibSilo mints a very large amount of stalk and roots for 0x7922... and calls incrementBipRoots, inflating BIP‑18’s recorded roots tally.0x7922..., the helper contract calls GovernanceFacet::vote for BIP‑18, causing governance to read the updated roots and conclude that BIP‑18 meets quorum and supermajority thresholds. In the same transaction, 0x7922... calls GovernanceFacet::emergencyCommit(18), which, seeing thresholds satisfied and timing constraints met, executes the BIP‑18 diamond cut.0xE5eCF7.... This init code reads Bean and Bean‑ETH LP balances from the Beanstalk diamond and transfers:
36,084,584.376516 BEAN (36084584376516 units, 6 decimals), and0.540716100968756904 BEAN‑ETH Uniswap V2 LP (540716100968756904 units, 18 decimals)0xc1e0... to helper contract 0x7922..., as shown in the ERC20 deltas above.0x1c5d...’s ETH balance increases by 24,829.778987126196402368 ETH (delta_wei = 24829778987126196402368), while gas costs for the transaction are approximately 0.337923336129829947 ETH. The net result is a large positive profit in ETH terms.The crucial point is that the governance checks in vote and emergencyCommit rely on roots that can be inflated and then discarded within a single transaction, allowing a flash‑loan‑based takeover of the treasury without any durable stake.
The adversary-related cluster accounts are:
0xf5a6..., 0x68cdec0a..., 0xcd31466...).0xcd31466.../balance_diff.json.contractAddress field).artifacts/root_cause/data_collector/iter_2/address/1/0x728a....erc20_balance_deltas in 0xcd31466.../balance_diff.json.erc20_balance_deltas.The primary victims are:
0xc1e088fc1323b20bcbee9bd1b9fc9546db5624c5;0xdc59ac4fefa32293a95889dc396682858d52e5db; and0x87898263b6c5babe34b4ec53f22d98430b91e371.The attacker’s end-to-end strategy follows three clear stages:
Adversary initial Silo funding
0xf5a698984485d01e09744e8d7b8ca15cd29aa430a0137349c8c9e19e60c0bb9d (block 14595189, Ethereum chainid 1).depositBeans).0x1c5d... deposits Bean into the Beanstalk Silo, establishing initial stalk and roots for later governance use.artifacts/root_cause/data_collector/iter_2/tx/1/0xf5a69898.../trace.cast.log plus SiloFacet/BeanSilo/LibSilo sources.BIP‑18 proposal and configuration
0x68cdec0ac76454c3b0f7af0b8a3895db00adf6daaf3b50a99716858c4fa54c6f (block 14595906, chainid 1).GovernanceFacet::propose via diamond fallback.0x1c5d... creates BIP‑18, sets its parameters (including the malicious init delegatecall), and casts an initial vote with roots recorded in AppStorage.Governance. No ERC20 balances move in this transaction.artifacts/root_cause/seed/1/0x68cdec0a.../metadata.json, .../balance_diff.json, .../trace.cast.log, and artifacts/root_cause/data_collector/iter_1/tx/1/0x68cdec0a.../receipt.json showing Proposal and Vote events.Flash-loan governance takeover and treasury drain
0xcd314668aaa9bbfebaf1a0bd2b6553d01dd58899c508d4729fa7311dc5d33ad7 (block 14602790, chainid 1).0x728a... is deployed.0x7922... deposits Bean and Bean‑ETH LP into the Silo, minting roots and increasing BIP‑18’s roots tally via LibSilo.0x7922... calls GovernanceFacet::vote for BIP‑18 and then GovernanceFacet::emergencyCommit(18).0x7922....0x1c5d... with a large ETH-denominated profit.artifacts/root_cause/seed/1/0xcd31466.../trace.cast.log and .../balance_diff.json, plus Beanstalk Silo and GovernanceFacet sources under data_collector/iter_2/contract/1/0xc1e0... and 0x448d33....The adversary’s strategy satisfies the ACT definition:
propose, vote, emergencyCommit) are not owner- or admin-gated; they are reached through the diamond fallback with standard calldata and gas.14602790.Therefore, an unprivileged adversary-related cluster with enough off-chain capital and the ability to replicate the DeFi routing could reproduce the same strategy and success predicate.
From the profit transaction’s ERC20 deltas in artifacts/root_cause/seed/1/0xcd31466.../balance_diff.json, the Beanstalk diamond 0xc1e0... loses:
0xdc59ac4fefa32293a95889dc396682858d52e5db)
delta = -36084584376516 unitsdecimals = 636,084,584.376516 BEAN.0x87898263b6c5babe34b4ec53f22d98430b91e371)
delta = -540716100968756904 unitsdecimals = 180.540716100968756904 BEAN‑ETH UNI‑V2 LP tokens.Matching positive deltas appear for attacker helper contract 0x7922..., confirming that the full Bean and Bean‑ETH LP treasury balances were transferred from the Beanstalk diamond to an adversary-related account.
On the profit side, the native balance deltas for EOA 0x1c5d... in the same transaction show:
before_wei = 27390250384248195067after_wei = 24857169237510444597435delta_wei = 24829778987126196402368Converting to ETH (1 ETH = 10^18 wei), this corresponds to a gross increase of approximately:
24829778987126196402368 wei / 1e18 ≈ 24829.778987126196402368 ETH
The gas cost, computed as gasUsed * effectiveGasPrice from the receipt, is approximately 0.337923336129829947 ETH. Thus, the transaction yields a clear positive ETH-denominated profit for the adversary, while the Beanstalk protocol loses essentially its entire Bean and Bean‑ETH LP treasury.
This report focuses on these on-chain treasury movements from the Beanstalk diamond to attacker-related addresses. Protocol-wide downstream effects on individual Silo depositors and secondary markets are not quantified here.
artifacts/root_cause/data_collector/iter_2/contract/1/0xc1e088fc1323b20bcbee9bd1b9fc9546db5624c5/sourceartifacts/root_cause/data_collector/iter_2/contract/1/0x448d330affa0ad31264c2e6a7b5d2bf579608065/source0xcd314668aaa9bbfebaf1a0bd2b6553d01dd58899c508d4729fa7311dc5d33ad7 (Ethereum mainnet, block 14602790)artifacts/root_cause/seed/1/0xcd31466.../trace.cast.logartifacts/root_cause/seed/1/0xcd31466.../balance_diff.json0x68cdec0ac76454c3b0f7af0b8a3895db00adf6daaf3b50a99716858c4fa54c6f (Ethereum mainnet, block 14595906)artifacts/root_cause/seed/1/0x68cdec0a.../metadata.jsonartifacts/root_cause/seed/1/0x68cdec0a.../balance_diff.jsonartifacts/root_cause/seed/1/0x68cdec0a.../trace.cast.logartifacts/root_cause/data_collector/iter_1/tx/1/0x68cdec0a.../receipt.json0xf5a698984485d01e09744e8d7b8ca15cd29aa430a0137349c8c9e19e60c0bb9d (Ethereum mainnet, block 14595189)artifacts/root_cause/data_collector/iter_2/tx/1/0xf5a69898.../trace.cast.log