# Governance attack on Extraordinary Proposals

Ajna's Extraordinary Funding vote threshold mixed treasury and non-treasury token units, letting a 71% holder pass a max-treasury proposal and drain the treasury across successive proposals.

- Payout: Contest reward
- Severity: medium
- Program: Ajna Protocol
- Credited: 0xRobocop
- Disclosed: 2023-06-29
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-05-ajna-findings/issues/164
- Library page: https://bugbountylibrary.com/r/c4%3A2023-05-ajna%3AM-12
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:governance

**Target:** GrantFund Extraordinary Funding governance contract
**Root cause:** The vote constraint compares votesReceived (a slice of non-treasury tokens) against tokensRequested_ (an absolute treasury-token amount) plus a non-treasury slice, mixing units. The requested treasury amount is not scaled by TreasuryT/NonTreasuryT, so the required vote percentage is understated.
**Steps:**
1. Deploy GrantFund, fund treasury with 300M AJNA; total supply 1B, non-treasury 700M.
2. Attacker holds 385M, delegates 115M from holders to self => 500M voting power (~71.4% of non-treasury).
3. Submit extraordinary proposal requesting 150M (50% of treasury) via `transfer(attacker, 150M)` calldata.
4. Call `voteExtraordinary(proposalId)`; state becomes Succeeded despite whitepaper requiring 100% of non-treasury.
5. Call `executeExtraordinary(targets, values, calldatas, keccak256(description))` to transfer 150M to attacker.
6. Repeat: now 535M voting power (~62.94% of 850M non-treasury) passes a 45% treasury request without prior delegators; iterate until treasury drained.
**How found:** Compared the whitepaper's percentage-based threshold formula (MT + requested treasury %) against the code's absolute-token formula `votesReceived >= tokensRequested_ + _getSliceOfNonTreasury(minThresholdPercentage)`, noticing the treasury amount was not normalized by TreasuryT/NonTreasuryT.
**Exploitation:** Attacker accumulates ~55% of non-treasury supply (self + delegated), submits an extraordinary proposal whose calldata transfers treasury tokens to itself, votes, and executes. Because the required threshold shrinks as treasury decreases and attacker balance grows, each subsequent proposal needs a smaller relative share, allowing solo drain of the treasury.
**Escalation:** Iterative proposals: each successful drain increases attacker's non-treasury share and shrinks treasury, lowering the required vote percentage for the next proposal until the attacker alone can pass max requests.
**Insight:** When a spec is written in percentages but code compares raw token amounts, check every term's unit; a treasury-token amount added to a non-treasury slice silently understates the required quorum, and the error compounds as treasury shrinks.
