Closed c4-submissions closed 11 months ago
bytes032 marked the issue as sufficient quality report
bytes032 marked the issue as primary issue
It is invalid, because the paymaster can consume at most gasLeft
because the nearCall
forwards this amount to that frame. So, consuming this gas, will reduce the refund amount as well.
miladpiri (sponsor) disputed
GalloDaSballo marked the issue as unsatisfactory: Invalid
Lines of code
https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L1425-L1447 https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L2160-L2170
Vulnerability details
Impact
When transaction provide paymaster to provide gas payment, paymaster's
ZKSYNC_NEAR_CALL_callPostOp
can be used to do other operation/external call that modify storage and use more gas than it should be.Proof of Concept
If L2 transaction is triggered and paymaster parameter provided, it will first make sure paymaster paid for gas via
ensurePayment
inside transaction validation.https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L1286-L1305
https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L656-L732
Then after all transaction execution is done, it will trigger
refundCurrentL2Transaction
and triggerZKSYNC_NEAR_CALL_callPostOp
ifgasLeft
left is not 0 andpaymaster
provided.https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L1401-L1476
https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L2087-L2171
The problem is this
ZKSYNC_NEAR_CALL_callPostOp
is not protected with hook that prevent operation/external call that modify storage, this will allowpostTransaction
to do operation and use gas more thangasLeft
and basically do more operation that what is paid.https://github.com/code-423n4/2023-10-zksync/blob/main/code/system-contracts/bootloader/bootloader.yul#L1438-L1447
as we can see, it will only set
gasLeft
to 0, even thoughgasSpentByPostOp
can be much bigger thangasLeft
.Foundry PoC :
In the test scenario, we want to simulate
postTransaction
to do external call and modify the storage value on the target contract.Modify the
TestnetPaymaster
contract insidecode/contracts/zksync/contracts/TestnetPaymaster.sol
to this :Add
MockChange
contract tocode/contracts/zksync/contracts/MockChange.sol
:Add this test file to
code/contracts/zksync/test/reentrancy.test.ts
:Run the test :
Output :
NOTE : The coded PoC verify that
postTransaction
allowed to do external call operation and modify storage. This can be leveraged to do expensive operation and use gas more than it should.Tools Used
Manual review
Recommended Mitigation Steps
Restrict
ZKSYNC_NEAR_CALL_callPostOp
so it can't write to external storage and make sure not used gas more than what already paid.Assessed type
Reentrancy