# DAO proposals can be executed by anyone due to vulnerable TimelockController

Notional's GovernorAlpha inherited a vulnerable TimelockController whose batch execution checked scheduling after execution, letting any proposer self-schedule and seize DAO admin roles.

- Payout: Audit contest
- Severity: high
- Program: Notional
- Found by: cmichel
- Disclosed: 2021-10-01
- Write-up quality: 8/10
- Original: https://github.com/code-423n4/2021-08-notional-findings/issues/58
- Library page: https://bugbountylibrary.com/r/c4%3A2021-08-notional%3AH-02
- Tags: area:web3 domain:web3 impact:funds-loss impact:privesc kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:chained technique:source-review vuln:access-control vuln:governance vuln:privilege-escalation

**Target:** GovernorAlpha / TimelockController (Solidity governance contract)
**Root cause:** TimelockController._executeBatch verifies the operation was scheduled only after executing the batch, so a batch can include a call that schedules itself; Notional's executeProposal also dropped the Queued state check.
**Steps:**
1. Call `propose` with calldata containing the malicious batch (anyone meeting proposalThreshold).
2. Call `executeProposal(proposalId, ...)` with batch: `grantRole(TIME_LOCK_ADMIN, attackerContract)`, `grantRole(EXECUTOR, attackerContract)`, `grantRole(PROPOSER, attackerContract)`, `updateDelay(0)`, then `attackerContract.hello()`.
3. `hello()` calls `timelock.schedule(args=[targets, values, datas, ...])` with the same args, so the id is scheduled during execution and the post-execution readiness check passes.
4. Attacker contract now holds PROPOSER and EXECUTOR and can call `scheduleBatch`/`executeBatch` directly.
**How found:** Recognized that GovernorAlpha inherited a known-vulnerable OpenZeppelin TimelockController (GHSA-fg47-3c2x-m2wr) and that the custom executeProposal removed the Queued state check, widening the known executor-only bug to any proposer.
**Exploitation:** Attacker submits a proposal whose batch grants itself timelock admin/executor/proposer roles, sets delay to 0, and self-schedules via a helper contract call; after execution the attacker controls the timelock and can execute arbitrary DAO transactions, e.g. updating globalTransferOperator to steal all tokens.
**Escalation:** Privilege escalation from any proposer to full Timelock admin, enabling arbitrary DAO-controlled actions and token theft.
**Insight:** When a project forks or inherits a library contract, diff it against upstream security advisories and check whether local overrides (like removing a state require) widen the known exploit's preconditions.

