The Transaction struct allows proposers to specify an arbitrary data payload, which is later executed via a low-level .call() in _executeTransaction.
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.
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.
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.
A malicious multisig signer proposes a transaction with a crafted data payload.
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).
Other signers confirm the transaction, assuming it performs a benign action.
After the timelock expires, _executeTransaction executes the payload using .call().
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.
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.
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.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.