# Reentrancy on Flash Governance Proposal Withdrawal

withdrawGovernanceAsset in FlashGovernanceArbiter transfers tokens before deleting pendingFlashDecision, letting a reentrant ERC777-style asset drain the contract balance.

- Payout: Audit contest
- Severity: medium
- Program: Behodler
- Found by: kirk-baird
- Disclosed: 2022-03-24
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-01-behodler-findings/issues/154
- Library page: https://bugbountylibrary.com/r/c4%3A2022-01-behodler%3AM-02
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:reentrancy

**Target:** FlashGovernanceArbiter.withdrawGovernanceAsset (Solidity DAO contract)
**Root cause:** External IERC20.transfer call is made before deleting pendingFlashDecision, violating checks-effects-interactions.
**Steps:**
1. Call `assertGovernanceApproved(userA, target, false)` to create a pending decision with amount > 0.
2. Wait until `unlockTime < block.timestamp`.
3. Call `withdrawGovernanceAsset(target, asset)`; during `asset.transfer()` reenter the same function.
4. Repeat reentrant call until contract balance < pending amount, draining the asset.
**How found:** Code review of withdrawGovernanceAsset noting the external transfer precedes the delete of pendingFlashDecision, i.e. missing checks-effects-interactions.
**Exploitation:** Attacker uses a reentrant ERC777-style asset; on each transfer callback re-enters withdrawGovernanceAsset before the pendingFlashDecision entry is deleted, repeatedly withdrawing the same amount until the arbiter's balance is exhausted.
**Insight:** When auditing governance/escrow withdrawal functions, check whether the pending-record delete happens after the token transfer; any ERC777/hook-capable asset in the allowlist turns that ordering into a drain.
