MultiSig Timelock

First Flight #55
Beginner FriendlyWallet
100 EXP
Submission Details
Impact: high
Likelihood: high

Lack of Proposal Expiration

Author Revealed upon completion

Root + Impact

Description

  • Normal behavior: Proposals stay active until executed.

  • Issue: Old proposals remain valid indefinitely. A transaction proposed years ago could be executed if the threshold is met later, potentially when context has changed (e.g., price of asset changed).

struct Transaction {
// ...
uint256 proposedAt;
// No expiration time
}

Risk

Likelihood:

  • Reason 1 // Forgotten proposals accumulate

  • Reason 2 // Signers sign old txs without checking date

Impact:

  • Impact 1 // Execution of stale/irrelevant transactions

  • Impact 2 // Unexpected fund movement

Proof of Concept

Explanation: Propose a transaction, wait for a long time (e.g., 1 year), then confirm and execute. It succeeds.

vm.warp(block.timestamp + 365 days);
multiSigTimelock.confirmTransaction(oldTxnId);
multiSigTimelock.executeTransaction(oldTxnId);

Recommended Mitigation

Explanation: Add an expiresAt field to the Transaction struct or a global expiration constant (e.g., 14 days). Check expiration in executeTransaction.

+ if (block.timestamp > txn.proposedAt + PROPOSAL_VALIDITY_PERIOD) {
+ revert MultiSigTimelock__TransactionExpired();
+ }

Status: Valid (Design Flaw)


Support

FAQs

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

Give us feedback!