Summary
When MondrianWallet2::executeTransactionFromOutside
is called, the function don't verify if transaction is valid.
Vulnerability Details
We can see below that MondrianWallet2::executeTransactionFromOutside
calls _validateTransaction
but don't verify if the return is valid:
function executeTransactionFromOutside(Transaction memory _transaction) external payable {
_validateTransaction(_transaction);
_executeTransaction(_transaction);
}
Impact
Without this verification anyone can execute the transaction becasue the signature is not verified and don't have the verification to check the required balance.
Tools Used
Foundry and Solidity
Proof of Concept
Add the following PoC to the test/ModrianWallet2Test.t.sol
:
function testZkExecuteOnlyValidTransactionsOnExecuteTransactionFromOutside() public {
address anonymousUser = makeAddr("anonymousUser");
address dest = address(usdc);
uint256 value = 0;
bytes memory functionData = abi.encodeWithSelector(ERC20Mock.mint.selector, address(mondrianWallet), AMOUNT);
Transaction memory transaction =
_createUnsignedTransaction(anonymousUser, 113, dest, value, functionData);
bytes32 unsignedTransactionHash = MemoryTransactionHelper.encodeHash(transaction);
uint8 v;
bytes32 r;
bytes32 s;
uint256 fakeKey = 0xac293483920;
(v, r, s) = vm.sign(fakeKey, unsignedTransactionHash);
transaction.signature = abi.encodePacked(r, s, v);
vm.prank(anonymousUser);
vm.expectRevert(0x59f73058);
mondrianWallet.executeTransactionFromOutside(transaction);
}
And run: forge test --zksync --system-mode=true --match-test testZkExecuteOnlyValidTransactionsOnExecuteTransactionFromOutside
Recommendations
Verify the return of _validateTransaction
:
function executeTransactionFromOutside(Transaction memory _transaction) external payable {
- _validateTransaction(_transaction);
+ bytes4 magic = _validateTransaction(_transaction);
+ if (magic != ACCOUNT_VALIDATION_SUCCESS_MAGIC) {
+ revert MondrianWallet2__InvalidSignature();
+ }
_executeTransaction(_transaction);
}