The contract’s lifecycle:
Proposal is Queued:
When a proposal moves to state Succeeded, the Governance contract calls _queueProposal(...), which schedules the operation in the timelock via:
Proposal is Canceled:
The contract’s cancel(...) sets proposal.canceled = true;, changing the local state to Canceled. However, no code calls _timelock.cancelOperationBatch(...) or similar.
Timelock Operation Remains:
In many standard timelocks, anyone can call executeBatch(...) once an operation is “ready.” The timelock itself does not know that Governance canceled the proposal. If the timelock does not require Governance to confirm again, the operation is still queued and can be executed by any user who calls:
Hence, a “canceled” proposal can still be executed if the timelock is never explicitly canceled.
Proposal Created and Queued
Governance identifies a successful proposal and calls _queueProposal(...), scheduling the operation in the timelock.
Cancellation
Some event triggers the Governance cancel(...) function (e.g., the proposer’s votes dropped below threshold or the proposer explicitly cancels). The proposal is set to canceled = true on Governance’s side.
Timelock Execution
Because the timelock never receives a “cancel operation” command, the queued operation remains pending. Once the timelock’s getMinDelay() elapses, anyone can call timelock.executeBatch(...) to finalize the transaction. The contract does not revert simply because Governance’s local state is canceled.
Bypassing the Governance Decision
The canceled proposal’s changes are still applied, undermining Governance authority.
Protocol Integrity Risk
If the canceled proposal was supposed to be halted due to new information or a lost majority, it can still pass externally in the timelock, enacting potentially harmful or undesired changes.
Integrate Timelock Cancel
In cancel(...), if the proposal is already queued, call something like:
That way, the timelock itself is also told to cancel the scheduled operation.
Enforce Governance
Some timelock designs allow only the governance contract (or an admin) to call executeBatch(...). Confirm that the timelock does not permit arbitrary external addresses to call it. If it does, you must explicitly cancel in the timelock to prevent unstoppable execution.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.