# Yam Finance: dormant-DAO quorum takeover drains UMA farms

Attacker bought ~3.3% of YAM, self-delegated, and cleared a dormant DAO's quorum alone, taking the Timelock and draining legacy UMA farming contracts for ~$121K.

- Payout: Real-world hack
- Severity: high
- Program: YamFinance
- Disclosed: 2026-09-12
- Write-up quality: 8/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2026-09/YamFinance_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20260912-yamfinance
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity technique:recon technique:source-review vuln:access-control vuln:business-logic

**Target:** Compound-style GovernorAlpha + Timelock governance and UMA farming contracts
**Root cause:** GovernorAlpha quorum (4% of supply) and proposal threshold (1%) were low enough that a single ~3.3% holder self-delegating cleared both with zero opposing votes; the Timelock was the governor's admin and also gov of the farming contracts, so a single setPendingAdmin proposal handed full protocol control.
**Steps:**
1. Acquire ~504,427 YAM (~3.3% supply) on open market via aggregator swap (block 25884984)
2. `YAM.delegate(attacker)` to self-delegate voting weight (~2.016e29 > quorumVotes 2e29 and > proposalThreshold 5e28)
3. `GOV.propose([TIMELOCK],[0],["setPendingAdmin(address)"],[abi.encode(attacker)],"0x")` -> proposal #45
4. `GOV.castVote(45, true)`; wait votingPeriod (12345 blocks)
5. `GOV.queue(45)`; warp 5-day timelock delay (432000s)
6. `GOV.execute(45)` -> `TIMELOCK.acceptAdmin()` to become timelock admin
7. Queue+execute `setDelay(43200)` to shorten future timelock to 12h
8. Queue+execute `_setPendingGov(attacker)` on UMAFarmingMar and UMAFarmingFeb via timelock, then call `_acceptGov()` directly
9. As gov call `_settleExpired()` to release WETH collateral, then `masterFallback(WETH, transfer(attacker,balance))` and same for UMA to drain
10. Cash out via FixedFloat to ~48.15 ETH
**How found:** Recognized the DAO was dormant with near-zero turnout, so a stake just above quorumVotes (4% supply) could pass a proposal unopposed; read verified GovernorAlpha state() logic confirming no minimum-for beyond quorum and no requirement for other voters, and traced that the Timelock was both governor admin and farming-contract gov, making a single setPendingAdmin proposal sufficient for full takeover.
**Exploitation:** Real at-risk capital (~504K YAM) held through the full ~12-day governance cycle; no flash loan. Single-action proposal setPendingAdmin(attacker) on the Timelock, then used timelock admin rights to seize gov of both UMA farming contracts and invoke the gov-only masterFallback escape hatch to transfer WETH and UMA balances to the attacker.
**Escalation:** Timelock admin -> gov of both farming contracts -> _settleExpired to unlock collateral -> masterFallback arbitrary call to sweep WETH and UMA.
**Insight:** On Compound-style GovernorAlpha forks, compare quorumVotes()/proposalThreshold() against real delegate turnout: if a single holder can exceed quorum with zero against-votes, a dormant DAO is takeover-able with market-bought tokens. Also check whether the Timelock is the gov/admin of downstream contracts with gov-only escape hatches like masterFallback.
