MultiSig Timelock

First Flight #55
Beginner FriendlyWallet
100 EXP
View results
Submission Details
Impact: medium
Likelihood: medium
Invalid

Proposing Transactions with Fewer Than 3 Signers Leads to Pinned (Stuck) Transactions That Cannot Be Executed

The contract allows the owner to propose transactions regardless of the current signer count. However, execution requires exactly 3 confirmations (REQUIRED_CONFIRMATIONS = 3). If the signer count drops below 3 (e.g., via revokeSigningRole, possible down to 1), proposed transactions can accumulate but never reach the required confirmations, effectively "pinning" them in a pending state. This could lock funds if the contract holds ETH, as no withdrawals can occur until more signers are added.

Description: The contract uses a fixed confirmation threshold of 3 (REQUIRED_CONFIRMATIONS) for executing transactions, but does not prevent proposals when the current number of signers (s_signerCount) is below this threshold. Proposals can be made via proposeTransaction (restricted to the owner), incrementing s_transactionCount and storing the transaction details. Signers can attempt to confirm via confirmTransaction, but if fewer than 3 signers exist, the confirmation count can never reach 3.

In _executeTransaction, it checks if (txn.confirmations = REQUIRED_CONFIRMATIONS)

  • revokeSigningRole (allows reduction to 1 or 2 signers)

  • _executeTransaction (enforces fixed 3 confirmations)

Impact:

  • Funds in the contract become inaccessible if signers drop below 3 after proposals.

  • Wasted gas on futile confirmations/revocations for pinned transactions.

  • Reduced usability in a multisig setup, as it doesn't fail-fast on proposals that are doomed to fail.

  • Potential for denial-of-service if many invalid proposals are made, bloating storage (though limited by owner-only proposals).

Proof of Concept (Conceptual):

  1. Deploy contract (1 signer: owner).

  2. Grant 2 more signers (now 3).

  3. Propose a transaction (ID 0).

  4. Revoke 2 signers (now 1 signer).

  5. Attempt to confirm/execute ID 0: Fails due to insufficient confirmations. Transaction is stuck.

Recommendation:

  • Add a check in proposeTransaction or _proposeTransaction: if (s_signerCount < REQUIRED_CONFIRMATIONS) revert MultiSigTimelock__InsufficientSignersForProposal();.

  • In revokeSigningRole, add: if (s_signerCount - 1 < REQUIRED_CONFIRMATIONS && _hasPendingTransactions()) revert ...; (implement _hasPendingTransactions to scan for unexecuted txns).

  • Alternatively, make REQUIRED_CONFIRMATIONS dynamic: e.g., uint256 required = min(REQUIRED_CONFIRMATIONS, s_signerCount); in an internal getter, ensuring it's at least 1. This maintains flexibility but requires careful testing.

Updates

Lead Judging Commences

kelechikizito Lead Judge 4 days ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!