MultiSig Timelock

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

Owner holds admin and signer roles, breaking claimed signer equality

Author Revealed upon completion

Owner holds admin and signer roles, breaking claimed signer equality

Description

The documentation explicitly states that :

“no individual signer has more power than any other once the role is granted”,

implying an egalitarian multisig governance model where all signers are equal.

  • However, the contract owner simultaneously holds:

    • the SIGNING_ROLE (granting full signer privileges), and

    • the DEFAULT_ADMIN_ROLE, which allows unilateral addition and removal of other signers.


    This dual-role setup gives the owner privileged authority that other signers do not possess. While all signers are equal at the transaction execution level, the owner retains exclusive administrative control over the signer set.


    As a result, the project completely loses its purpose because the main goal of a multisig wallet is to prevent a single compromised key from allowing an attacker to steal the funds. In this case, all security depends entirely on the owner key, so if it is compromised, an attacker can immediately access all funds.


Risk

Likelihood:

  • Medium/High: Even when the owner is not malicious, the wallet design inherently centralizes control in a single key. Every deployed instance immediately creates a structural imbalance, so the risk of funds being fully exposed in case of key compromise exists by design.

Impact:

  • High: The wallet security model is structurally centralized. Users may incorrectly assume true multisig protection, but a compromise of the owner key would immediately expose all funds.


Proof of Concept

This PoC demonstrates that the owner effectively holds full control over the wallet.

Add this to your MultiSigTimelockTest.t.sol file :

function testOwnerFullControl() public {
vm.deal(address(multiSigTimelock), 0.9 ether); //0.9 eth to skip the lock time
// Additional wallets controlled by the owner
address ownerSigner1 = makeAddr("ownerSigner1");
address ownerSigner2 = makeAddr("ownerSigner2");
address ownerReceiver = makeAddr("ownerReceiver");
// Setup: grant and revoke signers to illustrate full owner control
multiSigTimelock.grantSigningRole(SIGNER_TWO);
multiSigTimelock.grantSigningRole(SIGNER_THREE);
multiSigTimelock.revokeSigningRole(SIGNER_TWO);
multiSigTimelock.revokeSigningRole(SIGNER_THREE);
// Start a proposal and send to his wallet ownerReceiver all the funds
address to = ownerReceiver;
uint256 value = 0.9 ether;
bytes memory data = "";
uint256 txnId = multiSigTimelock.proposeTransaction(to, value, data);
// Grant signing roles to wallets controlled by owner
multiSigTimelock.grantSigningRole(ownerSigner1);
multiSigTimelock.grantSigningRole(ownerSigner2);
// Owner confirms
multiSigTimelock.confirmTransaction(txnId);
// Confirm with other wallets controlled by owner
vm.prank(ownerSigner1);
multiSigTimelock.confirmTransaction(txnId);
vm.prank(ownerSigner2);
multiSigTimelock.confirmTransaction(txnId);
// Check that confirmations are 3
MultiSigTimelock.Transaction memory txn = multiSigTimelock.getTransaction(txnId);
assertEq(txn.confirmations, 3);
// Execute the transaction
multiSigTimelock.executeTransaction(txnId);
// Check owner's balance receive the funds (0.9 eth)
uint256 ownerBalance = ownerReceiver.balance;
assertEq(ownerBalance, value);
}

Then run :

forge test --mt testOwnerFullControl -vvvvv

Recommended Mitigation

Two solutions, depending on your goal :

1) Enforce true multisig for admin actions (Recommended)

  • Move all owner operations (adding/removing signers, managing roles) behind a multisig mechanism itself.

  • Require a minimum number of existing signers to approve changes to signer membership or other critical roles.

  • This ensures no single key (even the owner) can unilaterally control the signer set.


2) Document clearly the trust assumptions

  • If owner centralization is intentional, clearly state in the README.md that the wallet security is entirely dependent on the owner key, and that it does not provide a trust-minimized multisig.

  • Users need to understand that the wallet behaves like a single-key wallet in practice.

Support

FAQs

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

Give us feedback!