MultiSig Timelock

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

Timelock starts at proposal time, not at quorum

Author Revealed upon completion

Scope
src/MultiSigTimelock.sol: Transaction.proposedAt, _executeTransaction

Root + Impact

Description

  • Normal behavior: Timelock should begin once enough signers approve a high-value action.

  • Issue: The delay is anchored to proposedAt, so an attacker can propose a 100+ ETH transfer, wait seven days off-chain, then gather three confirmations in one block and execute instantly without any post-approval delay.

uint256 executionTime = txn.proposedAt + requiredDelay; // delay counted from proposal time

Risk

Likelihood:

  • Reason 1 // Signers often batch approvals after review windows

  • Reason 2 // Attackers can pre-position proposals and only seek confirmations when opportune

Impact:

  • Impact 1 // High-value transfers or governance calls execute with effectively zero notice after approval

  • Impact 2 // Monitoring systems keyed off “confirmations reached” lose the expected buffer window

Proof of Concept

Explanation: Propose a 150 ETH transfer, wait 7 days, then obtain three confirmations in a single block. Execution succeeds immediately because proposedAt + SEVEN_DAYS_TIME_DELAY already elapsed.

// propose at t0, sleep 7 days off-chain, collect 3 confirms at t0+7d, execute in same block

Recommended Mitigation

Explanation: Start the timelock when the final confirmation is recorded (or when the quorum threshold is first met) by storing readyAt on threshold crossing.

+ uint256 readyAt;
+ if (validConfirmations == REQUIRED_CONFIRMATIONS && readyAt == 0) readyAt = block.timestamp;
+ if (block.timestamp < readyAt + requiredDelay) revert MultiSigTimelock__TimelockHasNotExpired(readyAt + requiredDelay);

Status: Valid (Design Flaw)


Support

FAQs

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

Give us feedback!