Multisig systems typically allow a proposed transaction to be canceled/invalidated (e.g., by the proposer or by a quorum of signers) when it’s found to be malicious, outdated, or otherwise undesirable. Canceled transactions should no longer be confirmable or executable.
Once a transaction is proposed, there is no cancellation mechanism. The Transaction struct has no canceled flag, there is no cancelTransaction function, and existing flows (confirmTransaction, revokeConfirmation, executeTransaction) do not check for cancellation. The transaction remains in storage indefinitely and can be reconfirmed/executed at any future time if quorum is later met.
Likelihood: Medium
During normal operations, teams often discover a proposed transaction is wrong or risky after it’s created. Because there’s no cancel path, that transaction remains actionable forever.
Over time (e.g., after membership changes or incident response), new or different signers may accidentally (or intentionally) reconfirm and execute the stale transaction.
Impact: Medium
Governance & safety risk: Malicious/outdated proposals can be executed later, even after signers attempted to “abandon” them via revocations.
Operational overhead & confusion: Unbounded accumulation of stale proposals increases surface area for mistakes and complicates audits, monitoring, and tooling.
Copy the code below to MultiSigTimeLockTest.t.sol.
Run command forge test --mt testPendingTransactionPersistsWithoutCancellation -vv.
Output:
Introduce an explicit cancellation state and enforce it across all flows:
1. Extend the Transaction struct;
2. Add a notCanceled modifier;
3. Gate confirmTransaction & executeTransaction with notCanceled;
4. Provide an admin/quorum-based cancel function.
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.
The contest is complete and the rewards are being distributed.