# TemporalGovernor can be bricked by guardian

Guardian pauses TemporalGovernor, then grantGuardiansPause disables unpause paths and renounceOwnership removes the owner, permanently bricking cross-chain governance.

- Payout: Audit contest
- Severity: medium
- Program: Moonwell
- Found by: immeas
- Disclosed: 2023-10-04
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2023-07-moonwell#m-06
- Library page: https://bugbountylibrary.com/r/c4%3A2023-07-moonwell%3AM-06
- Tags: area:web3 domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:chained technique:source-review vuln:access-control vuln:business-logic vuln:governance

**Target:** TemporalGovernor cross-chain governance contract
**Root cause:** grantGuardiansPause lacks whenNotPaused and can be executed while paused, breaking assert(!guardianPauseAllowed) in permissionlessUnpause/togglePause; inherited Ownable lets the guardian renounce ownership, removing the only path to revokeGuardian.
**Steps:**
1. Guardian calls `governor.togglePause()` to pause the contract.
2. Governance sends cross-chain instruction calling `grantGuardiansPause`; guardian executes it via `fastTrackProposalExecution` while still paused, setting guardianPauseAllowed=true.
3. Guardian calls `governor.renounceOwnership()` from inherited Ownable, leaving owner=address(0).
4. `executeProposal` reverts with `Pausable: paused`; `permissionlessUnpause` reverts on `assert(!guardianPauseAllowed)`; no owner remains to call revokeGuardian.
**How found:** Code review of pause/unpause state machine: noticed grantGuardiansPause callable while paused contradicts assert(!guardianPauseAllowed), and that inherited Ownable exposes renounceOwnership bypassing revokeGuardian's special logic; combined both into a bricking chain.
**Exploitation:** Malicious guardian pauses, executes a governance grantGuardiansPause payload via fastTrackProposalExecution, then renounces ownership, leaving the contract paused with no unpause or execution path; guardian can also hold the contract hostage before renouncing.
**Insight:** When a contract inherits Ownable alongside custom ownership/guardian logic, check whether inherited renounceOwnership/transferOwnership bypasses the custom revocation path; also check pause-gated setters that can re-enable flags while paused, breaking unpause asserts.

