MultiSig Timelock

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

Mismatch Between Documented Signer Privileges and Enforced Owner-Only Proposals

Description

The proposeTransaction() function is restricted by the onlyOwner modifier, allowing only the contract owner to create transaction proposals. This behavior contradicts the documented design, which states that any address holding the SIGNING_ROLE should be able to propose transactions. As a result, signers are limited to confirming and executing transactions but cannot independently initiate proposals.

This creates a mismatch between the contract’s documented governance model and its actual implementation.


Impact

  • centralization risk, the owner becomes a single point of control for all transaction initiation.

  • Prevents signers from proposing urgent or corrective transactions if the owner is unavailable, compromised, or unresponsive.

  • Breaks assumptions made by users, auditors, and integrators who rely on the documentation.

  • Reduces fault tolerance and decentralization guarantees expected from a multisignature wallet.


Affected Area

permalink: https://github.com/CodeHawks-Contests/2025-12-multisig-timelock/blob/3c88fea850b25724b71778bdc7bfe96c3bd97b63/src/MultiSigTimelock.sol#L249

Proof of Concept

function testSignerCannotProposeTransaction() public {
multiSigTimelock.grantSigningRole(SIGNER_TWO); // make SIGNER_TWO as signer
vm.deal(SIGNER_TWO, OWNER_BALANCE_ONE);
//signer trying to propose transaction
vm.prank(SIGNER_TWO);
vm.expectRevert();
multiSigTimelock.proposeTransaction(
SPENDER_ONE,
OWNER_BALANCE_ONE,
hex""
);
}

output:

Ran 1 test for test/unit/MultiSigTimelockTest.t.sol:MultiSigTimeLockTest
[PASS] testSignerCannotProposeTransaction() (gas: 102525)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.18ms (185.30µs CPU time)
Ran 1 test suite in 19.89ms (4.18ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)

Recommended Mitigation

replace the onlyOwner modifier with role-based access control

onlyRole(SIGNING_ROLE)

This allows any authorized signer to propose transactions while preserving multisignature confirmation and timelock security.

Updates

Lead Judging Commences

kelechikizito Lead Judge
11 days ago
kelechikizito Lead Judge 4 days ago
Submission Judgement Published
Invalidated
Reason: Other

Support

FAQs

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

Give us feedback!