# Only guardian can change guardian

TemporalGovernor reuses Ownable's owner as pause guardian, so governance cannot transfer the guardian role, only revoke it to address(0).

- 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-05
- Library page: https://bugbountylibrary.com/r/c4%3A2023-07-moonwell%3AM-05
- Tags: area:web3 domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:access-control vuln:governance

**Target:** TemporalGovernor.sol cross-chain governance contract (Solidity)
**Root cause:** guardian is implemented as OpenZeppelin Ownable's owner, and transferOwnership is not overridden, so only the current guardian can hand off the role; governance (address(this)) cannot.
**Steps:**
1. Queue a proposal whose payload calls `Ownable.transferOwnership(newAdmin)` on the governor via mockCore.setStorage and governor.queueProposal("").
2. Warp past proposalDelay and call governor.executeProposal("").
3. Execution reverts with `Ownable: caller is not the owner` because msg.sender to Ownable is the governor contract, not the owner.
**How found:** Docs flagged the pause guardian as an area of concern; reviewer read TemporalGovernor's use of Ownable and noticed transferOwnership was not overridden, then wrote a Foundry test to confirm governance cannot rotate the guardian.
**Exploitation:** Not an attacker exploit; a governance/guardian conflict-of-interest scenario. If guardian refuses to abstain, governance's only recourse is revokeGuardian, setting owner to address(0) and permanently disabling pause.
**Insight:** When a contract aliases Ownable's owner to a privileged operational role (pauser/guardian), check whether governance can rotate that role; unoverridden transferOwnership makes the role self-perpetuating and forces governance into a destructive revoke.

