Owner of TemporalGovernor could revoke ownership without unpausing the contract #394
Labels
bug
Something isn't working
downgraded by judge
Judge downgraded the risk level of this issue
grade-a
low quality report
This report is of especially low quality
Q-05
QA (Quality Assurance)
Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax
Lines of code
https://github.com/code-423n4/2023-07-moonwell/blob/fced18035107a345c31c9a9497d0da09105df4df/src/core/Governance/TemporalGovernor.sol#L256
Vulnerability details
Impact
The guardian of the TemporalGovernor contract is equal to the owner. The guardian can either revoke himself or be revoked through a governance proposal through the
revokeGuardian
function, which transfers ownership of the contract to address(0) and unpauses the contract if paused.https://github.com/code-423n4/2023-07-moonwell/blob/4aaa7d6767da3bc42e31c18ea2e75736a4ea53d4/src/core/Governance/TemporalGovernor.sol#L205-L221
However, the owner can also revoke ownership through the
renounceOwnership
function inherited from the OpenZeppelin contract, in which case the contract would not be unpaused first.As the "normal" unpause functionality (
togglePause
) is only accessible to the owner, the contract would remain in a paused state untilpermissionlessUnpauseTime
, the time delay until the contract can be unpaused by anyone (set to 30 days in deploy script) has passed. During that time it would not be possible to queue or execute any proposals.The
permissionlessUnpause
function assumes thatguardianPauseAllowed
must be false whenever it is called. As a result, the function reverts ifguardianPauseAllowed
is true:https://github.com/code-423n4/2023-07-moonwell/blob/fced18035107a345c31c9a9497d0da09105df4df/src/core/Governance/TemporalGovernor.sol#L256
The function can only be called when the contract is paused and
guardianPauseAllowed
is set to false whenever the owner pauses the contract. However, this assumption is incorrect, asguardianPauseAllowed
can always be reset to true through a proposal, even when the contract is currently paused. Only the owner can execute proposals when the contract is paused.This assumption in the comments is also incorrect, as
lastPauseTime
can be reset to 0 through thegrantGuardiansPause
functionIn conclusion,
(1) the contract could enter a temporary paused state (30 days) if the owner calls the
renounceOwnership
function when the contract is paused(2) the contract could enter an irrevokable / permanent paused state if the owner pauses the contract, then reapproves himself as pauser through a fast-tracked proposal (
grantGuardiansPause
) and then calls therenounceOwnership
function. To my understanding, the owner can only reapprove himself if such a proposal passes the vote on the existing governance system.Proof of Concept
Add these tests to
TemporalGovernorExec.t.sol
Recommendations
Consider overriding the
renounceOwnership
function so that it reverts in all cases to ensure the ownership can only be renounced through therevokeGuardian
function.To address the incorrect invariant:
whenNotPaused
modifier to thegrantGuardiansPause
functionAssessed type
Governance
The text was updated successfully, but these errors were encountered: