MultiSig Timelock

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

Arbitrary calldata execution allows malicious multisig transactions

Author Revealed upon completion

Arbitrary calldata execution allows malicious multisig transactions

Description

The Transaction struct allows proposers to specify an arbitrary data payload, which is later executed via a low-level .call() in _executeTransaction.

(bool success,) = payable(txn.to).call{value: txn.value}(txn.data);

This design enables any multisig participant to propose a transaction that executes arbitrary calldata on an arbitrary target address. Once the required number of confirmations is reached and the timelock expires, the contract will blindly execute the provided payload without validating its intent or effects.

Risk

As a result, a malicious or compromised signer can craft a transaction that:

  • calls unexpected or dangerous functions,

  • interacts with external contracts in unintended ways,

  • performs state changes that are difficult for other signers to reason about by only inspecting raw calldata.

Because calldata validation is non-trivial and highly error-prone, other signers may approve a transaction without fully understanding its real execution behavior.

Impact

This issue allows arbitrary code execution through the multisig, which can lead to severe consequences depending on the crafted payload. Potential impacts include loss of funds, unauthorized approvals, unexpected contract interactions, or permanent protocol misconfiguration.

Even though multiple confirmations are required, the complexity and opacity of raw calldata significantly increase the risk of human error, making this a high-severity security risk.

Proof of Concept

  1. A malicious multisig signer proposes a transaction with a crafted data payload.

  2. The payload encodes a call to an unexpected or harmful function (for example, approving unlimited token allowances, triggering destructive external logic, or interacting with a malicious contract).

  3. Other signers confirm the transaction, assuming it performs a benign action.

  4. After the timelock expires, _executeTransaction executes the payload using .call().

  5. The malicious logic is executed successfully, causing unintended side effects.

No technical bypass is required — the attack relies purely on the ability to submit arbitrary calldata.

Recommended Mitigation

To significantly reduce the attack surface, it is recommended to remove support for arbitrary calldata execution entirely.

Specifically:

  • Restrict multisig transactions to ETH transfers only by enforcing txn.data.length == 0, or

  • Explicitly disallow calldata execution and remove the data field from the Transaction struct.

struct Transaction {
address to;
uint256 value;
- bytes data;
uint256 confirmations;
uint256 proposedAt;
bool executed;
}

This approach simplifies the security model, eliminates the risk of arbitrary execution, and ensures that all signers can clearly understand the effect of each transaction without needing to decode or audit raw calldata.

Support

FAQs

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

Give us feedback!