Open c4-submissions opened 1 year ago
bytes032 marked the issue as sufficient quality report
bytes032 marked the issue as primary issue
miladpiri marked the issue as disagree with severity
Deposit limitation is a temperoary feature implemented to protect users from depositing large amount of fund into the protocol while it is in alpha mode. So, issues like this does not cause damage to the protocol. So, medium can be a fair severity.
miladpiri (sponsor) confirmed
GalloDaSballo changed the severity to 2 (Med Risk)
The Warden has shown how the implementation of limits, which are indexed by address, will cause the bridge to be subject to the caps that should apply to a single wallet
Since the finding would deny functionality but can technically be removed, I think Medium Severity to be most appropriate
GalloDaSballo marked the issue as selected for report
Lines of code
https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/contracts/zksync/facets/Mailbox.sol#L236-L273
Vulnerability details
Impact
Detailed description of the impact of this finding. The flow bridgeProxy.deposit() -> L1WethBridge.deposit() -> Mailbox.requestL2Transaction() allows one to deposit WETH from L1 to L2. However, when checking the deposit limit for a particular depositor, Mailbox.requestL2Transaction() checks the limit of msg.sender, which is the address of L1WethBridge. As a result, when the limit of the bridge is reached, nobody can deposit anymore, even though their limit is not reached yet. As a result, sooner or later, nobody will be able to use Zksync to deposit weth to L2 from L1.
Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.
The flow bridgeProxy.deposit() -> L1WethBridge.deposit() -> Mailbox.requestL2Transaction() allows one to deposit WETH from L1 to L2. However, when checking the deposit limit for a particular depositor, Mailbox.requestL2Transaction() checks the limit of msg.sender, which is the address of L1WethBridge.
https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/contracts/zksync/facets/Mailbox.sol#L236-L273
As a result, when the limit of the bridge is reached, nobody can deposit anymore, even though their limit is not reached yet. As a result, sooner or later, nobody will be able to use Zksync to deposit weth to L2 from L1.
The following POC confirms my finding: 1) We set the deposit limit to 10 ether. 2) user1 deposits 3 ether of weth and sends 0.1 ether of eth, this is successful, we have s.totalDepositedAmountPerUser[L1WethBridge] = 3.1 ether. 3) user2 deposits 4 ether of weth and 0.1 ether of eth, this is successful, we have s.totalDepositedAmountPerUser[L1WethBridge] = 7.2 ether. 4) user3 deposits 2.7 ether of weth and 0.1 weth, this is successful s.totalDepositedAmountPerUser[L1WethBridge] = 10 ether, it has not exceeded the limit; however, if user3 deposits
2.7 ether + 1
of weth and 0.1 weth, then it will revert since now s.totalDepositedAmountPerUser[L1WethBridge] = 10 ether + 1. Note that user3 has not exceeded its limit. However, the limit check is onL1WethBridge
, not onuser3
, and that is the problem.The following test file is a modification of the test file: zksync/code/contracts/ethereum/test/foundry/unit/concrete/Bridge/L1WethBridge/Deposit.t.sol. The test function is test_DepositExceedLimit().
Please run the following command under zksync/code/contracts/ethereum:
forge test --match-test test_DepositExceedLimit -vv
The following line has been commented out to skip the check of merkle root:
https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/contracts/zksync/facets/Mailbox.sol#L142
Tools Used
Foundry, VScode
Recommended Mitigation Steps
Check the limit of the real depositor instead of the limit for the L1WethBridge.
Assessed type
Math