code-423n4 / 2023-10-zksync-findings

3 stars 0 forks source link

Gas Manipulation Risk in Paymaster #586

Open c4-submissions opened 11 months ago

c4-submissions commented 11 months ago

Lines of code

https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L703

Vulnerability details

Impact

Gas Manipulation Risk in Paymaster-Enabled Transactions can lead to unexpected transaction failures, even when users provide sufficient gas and fees, due to potential gas consumption manipulation by malicious paymasters. This may result in user funds being spent without achieving the desired transaction outcome.

Proof of Concept

Imagine there's an L2 transaction in which the fee is covered by a paymaster. During validation of this transaction, all the remaining gas (referred to as gasLimitForTx) is directed to the function ZKSYNC_NEAR_CALL_validateTx using the "near-call" mechanism. https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L1204

Now, within the ZKSYNC_NEAR_CALL_validateTx function, after the validateTransaction is called in the DefaultAccount contract, the function ensurePayment is invoked to manage the transaction fee payments. https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L1302

Since the paymaster address is not empty, the function validateAndPayForPaymasterTransaction is triggered. This function, in turn, calls validateAndPayForPaymasterTransaction in the paymaster contract. https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L703 https://github.com/code-423n4/2023-10-zksync/blob/main/code/contracts/zksync/contracts/TestnetPaymaster.sol#L14

Since the paymaster implementation is out of scope, to put it simply, the paymaster transfers tokens from the user to themselves and forwards the equivalent ETH amount to the Bootloader as the transaction fee. https://github.com/code-423n4/2023-10-zksync/blob/main/code/contracts/zksync/contracts/TestnetPaymaster.sol#L50 https://github.com/code-423n4/2023-10-zksync/blob/main/code/contracts/zksync/contracts/TestnetPaymaster.sol#L63

It's worth emphasizing that the gas allocated to the paymaster is determined by the remaining gas from the gasLimitForTx parameter, which is initially set using the near-call mechanism. https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L2034 https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L1204

The issue arises when the gas consumption within the paymaster exceeds expectations or if the paymaster intentionally consumes a substantial amount of gas. In such cases, there's a risk that the gas allocated for execution might not be sufficient, leading to execution failure.

For example, Alice initiates an L2 transaction with gasLimit = 10,000,000 and intends to allocate 6,000,000 gas to the destination address. During validation, the near-call mechanism forwards 10,000,000 - X gas to ZKSYNC_NEAR_CALL_validateTx, where X represents the gas consumed between lines 1292 and 1300. For simplicity, let's assume X = 1,000,000. Consequently, the remaining gas available for the ensurePayment function is 9,000,000. https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L1292-L1300

When ensurePayment is invoked, it calls the validateAndPayForPaymasterTransaction function within the paymaster, forwarding 9,000,000 gas. If the paymaster, for some reason, intentionally consumes 8,999,000 gas, upon returning to the l2TxValidation function, gasLeft is set to just 9,000,000 - 8,999,000 = 1,000. https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L1216

In the subsequent execution, having only 1,000 gas left, it's insufficient to execute the transaction as Alice originally intended (6,000,000 gas to the destination address). Thus, the transaction fails, and the remaining gas is entirely consumed, leading to a "success = false" result. https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L1271

Despite Alice providing a sufficient gasLimit, paying the fee in a specific token to the paymaster, and the paymaster subsequently covering the required fee in ETH, the transaction fails due to gas misuse by the paymaster. This problem arises because the entire remaining gas is sent to the paymaster, allowing the paymaster to potentially influence gas consumption in a way that leaves insufficient gas for the user's transaction execution to succeed.

Tools Used

Recommended Mitigation Steps

Consider implementing either of the following solutions:

Assessed type

Context

c4-pre-sort commented 10 months ago

bytes032 marked the issue as primary issue

c4-pre-sort commented 10 months ago

141345 marked the issue as sufficient quality report

miladpiri commented 10 months ago

Working as intended - a malicious paymaster can “take” the fee that user gave it, and fail transaction on purpose.

c4-sponsor commented 10 months ago

miladpiri (sponsor) disputed

c4-judge commented 9 months ago

GalloDaSballo changed the severity to QA (Quality Assurance)

GalloDaSballo commented 9 months ago

I believe that due to scoping, we cannot determine a Medium Severity

The paymaster is a contract that works in tandem with the AA contract, the Paymaster could cause issues, but it may also not