xanoutas/solidity-security-findings huggingface dataset:
Sending L2 ---> L1 message without paying gas for published data due to uint256 overflow
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-zksync//blob/main/contracts/L1Messenger.sol#L37


# Vulnerability details

## Impact
Due to this bug, a user can send arbitrarily long messages (greater than a certain length) from L2 to L1 without paying for the gas that is required for publishing data on L1. 

## Proof of Concept
Below is a PoC contract called "Test" that illustrates the bug. The state variable "messageLength" corresponds to the "_message.length" variable in line 37 of the L1Messenger.sol. "messageLength" has a specific value; messages with length >= "messageLength" can be passed from L2 to L1 without paying the required gas fees. 

This is asserted through the function "check()" in the PoC that contains only the vulnerable computation part of the L1Messenger.sol (basically, the computaion of "pubdataLen" in the unchecked scope). Due to the presence of the "unchecked { }" scope, the computation of "pubdataLen" can overflow for messages having length >= "messageLength". 

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.0;

contract Test {

    uint256 public messageLength = ((((2**256) - 64) / 32) * 32) - 31;

    function check() external view {

        unchecked {

            uint256 pubdataLen = ((messageLength + 31) / 32) * 32 + 64;
            assert(pubdataLen == 0);
        }
    }
} 

## Tools Used
Remix IDE

## Recommended Mitigation Steps
It is recommended to remove the "unchecked { }" scope currently used for calculating "pubdataLen". This is because messages can be arbitrarily long and thus, the computation of "pubdataLen" can overflow.
Possible loss of funds when withdrawing from L2 to L1
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-zksync/blob/main/contracts/L2EthToken.sol#L80
https://github.com/code-423n4/2023-03-zksync/blob/main/contracts/libraries/SystemContractHelper.sol#L48


# Vulnerability details

## Impact
### Context
To initiate a withdrawal from L2 to L1, a user can call `L2EthToken.withdraw` method, then funds will be available to calim on L1 via `finalizeEthWithdrawal`  method of **MailboxFacet**. 
```sh
function withdraw(address _l1Receiver) external payable override
```
https://github.com/code-423n4/2023-03-zksync/blob/main/contracts/L2EthToken.sol#L80

The mechanism behind this is that the`withdraw` method sends a constructed withdraw message to L1 via **L1Messenger**'s `sendToL1` method, then the user can use the message as a proof in order to claim the funds on L1.

```sh
        // Send the L2 log, a user could use it as proof of the withdrawal
        bytes memory message = _getL1WithdrawMessage(_l1Receiver, amount);
        L1_MESSENGER_CONTRACT.sendToL1(message);
```
https://github.com/code-423n4/2023-03-zksync/blob/main/contracts/L2EthToken.sol#L90-L91

### Possible loss of funds
If the withdrawal transaction succeeds, the user should be able to claim his/her funds on L1 always. However, there is a case where the withdrawal transaction succeeds even though the message wasn't sent to L1. This could happen if there is not enough gas during message sending. 
As a result, the user loses funds since the ether are burnt in L2 but can not be claimed on L1 due to the failure of sending the message to L1.


*Note: the `withdraw` method should be called via **MsgValueSimulator** since msg.value is set by the simulator.*

## Proof of Concept

The execution sequence as follows:
 ```mermaid
flowchart TD;
		subgraph L2EthToken
    withdraw-->L2EthToken._getL1WithdrawMessage(_getL1WithdrawMessage)
    end
		subgraph L1Messenger
sendToL1;		
		end
		subgraph SystemContractHelper
toL1;		
		end
		L2EthToken-->L1Messenger
		L1Messenger-->SystemContractHelper
```


Let's have a look at `SystemContractHelper.toL1` method:
```sh
    function toL1(bool _isService, bytes32 _key, bytes32 _value) internal {
        address callAddr = TO_L1_CALL_ADDRESS;
        assembly {
            // Ensuring that the type is bool
            _isService := and(_isService, 1)
            // This `success` is always 0, but the method always succeeds
            // (except for the cases when there is not enough gas)
            let success := call(_isService, callAddr, _key, _value, 0xFFFF, 0, 0)
        }
    }
```
https://github.com/code-423n4/2023-03-zksync/blob/main/contracts/libraries/SystemContractHelper.sol#L48


There is call to **TO_L1_CALL_ADDRESS** address, please note that this is just a simulation to zkSync VM-specific v1.3.0 opcodes. For more info, check this:
https://github.com/code-423n4/2023-03-zksync/blob/main/docs/VM-specific_v1.3.0_opcodes_simulation.pdf

As noticed, the method should always succeed except when there is
Reentrancy in `validateTransaction` function
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/DefaultAccount.sol#L66-L72
https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/DefaultAccount.sol#L77-L80


# Vulnerability details

## Impact
The contract can be called by an attacker several times until the money are depleted. The contract owner may suffer financial damages as a result of this vulnerability.

### Description
The `validateTransaction` function in line 66-71 accepts external calls and executes them, this feature makes the contract vulnerable to reentrancy attacks, an attacker can execute a malicious contract to trigger the `validateTransaction` function while the function is still in the execution process.
The attacker can then repeatedly call the contract to siphon funds.

## Proof of Concept
The `validateTransaction` function on lines 66–71 of this contract contains the susceptible code, It takes and handles external calls, so as a result, while the function is still being executed, an attacker can run a malicious contract to call the `validateTransaction` function. The attacker can then call the contract frequently to steal money.

Code snippet for the `validateTransaction` function:
```solidity
    function validateTransaction(
        bytes32, // _txHash
        bytes32 _suggestedSignedHash,
        Transaction calldata _transaction
    ) external payable override ignoreNonBootloader ignoreInDelegateCall returns (bytes4 magic) {
        magic = _validateTransaction(_suggestedSignedHash, _transaction);
    }
```
We can see that the `validateTransaction` function accepts external calls, and it calls the `_validateTransaction` function:

```solidity
 function _validateTransaction(
        bytes32 _suggestedSignedHash,
        Transaction calldata _transaction
    ) internal returns (bytes4 magic) {
 )
```

This `_validateTransaction` function can call other external functions and even other contracts, which makes it possible to execute a reentrancy attack.

Let's look at the following code to demonstrate the reentrancy attack concept:
```solidity
contract MaliciousContract {
    function attack(DefaultAccount _defaultAccount) external payable {
        bytes32 suggestedSignedHash = bytes32(0);
        Transaction calldata transaction;
        _defaultAccount.validateTransaction(suggestedSignedHash, transaction);
        _defaultAccount.withdraw(msg.sender, msg.value);
    }
}
```
The attack function in the "MaliciousContract" contract repeatedly calls the withdraw function before the vulnerable smart contract has had time to update the balance, this allows the attacker to drain the funds from the vulnerable smart contract.

We can see that we are calling the `validateTransaction` function of the `DefaultAccount` contract after executing the `validateTransaction` function, we are withdrawing the "ether" using the withdraw function in the `DefaultAccount` contract,
Bytecode Compressor Contract Replay Attack.
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/KnownCodesStorage.sol#L73-L75


# Vulnerability details

## Impact
Injection of duplicate code.

## Proof of Concept
In the `_markBytecodeAsPublished` function, the contract does not check whether a particular hash has already been added to the storage.

The contract only checks the current marker value of the hash, which is set to `0` by default, and if the value is still `0`, the hash is saved to the storage, and the contract emits an event `MarkedAsKnown`. This means that an attacker can replay a transaction with the same bytecode hash, and the contract will add the same hash again to the storage, resulting in duplicate code.

Vulnerable code:
https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/KnownCodesStorage.sol#L59-L79

## Tools Used

Manual audit

## Recommended Mitigation Steps
The contract should first check whether the hash has already been added to the storage before saving it again.

Updated code:
```solidity
function _markBytecodeAsPublished(
    bytes32 _bytecodeHash,
    bytes32 _l1PreimageHash,
    uint256 _l1PreimageBytesLen,
    bool _shouldSendToL1
) internal {
    if (getMarker(_bytecodeHash) == 0) {
        _validateBytecode(_bytecodeHash);

        if (_shouldSendToL1) {
            _sendBytecodeToL1(_bytecodeHash, _l1PreimageHash, _l1PreimageBytesLen);
        }

        // Save as known, to not resend the log to L1
        assembly {
            sstore(_bytecodeHash, 1)
        }

        emit MarkedAsKnown(_bytecodeHash, _shouldSendToL1);
+   } else {
+       emit AlreadyMarkedAsKnown(_bytecodeHash);
    }
}
```
`getBlockHashEVM()` function vulnerability leads to DoS attack
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/SystemContext.sol#L73-L79


# Vulnerability details

## Impact
By using the `getBlockHashEVM` function with erroneous input, an attacker can take advantage of this vulnerability to deprive the contract of gas and launch a denial of service (DoS) attack against the network, contracts and valid transactions will therefore be hindered or even rendered inaccessible.

### Description
The `SystemContext` contract's `getBlockHashEVM()` method is used to obtain the hash for a given block number, with a valid block number or range, the function does not verify the input, though the network may be subjected to a denial of service (DoS) attack if an attacker used this vulnerability to request `getBlockHashEVM()` for an erroneous block number or block range.

## Proof of Concept
The vulnerability exists in the contract because it does not validate the input for a valid block number or range before calling `blockhash`, which returns the hash of the given block. 

The line of code that calls `blockhash` without validation is:
https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/SystemContext.sol#L73-L74

A possible exploit scenario is as follows:

* Eve creates a malicious contract that calls `getBlockHashEVM` with an invalid block number or range, such as a negative number, a zero, or a number larger than 256.
* Eve sends a transaction to her contract, which then calls `getBlockHashEVM` on the vulnerable contract.
* The vulnerable contract tries to execute "blockhash" with an invalid input, which causes an exception and reverts the transaction.
* Eve repeats this process with different invalid inputs, causing many transactions to fail and consuming gas from other users.
* Eve performs a denial of service (DoS) attack on the network by preventing other transactions from being executed.

## Tools Used

Manual Audit

## Recommended Mitigation Steps
The `getBlockHashEVM()` method should be updated to incorporate input validation code.
The block number's validity and existence within the blockchain may be verified via the validation code.
The function should throw an exception or return a notice if the input is invalid.
https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/SystemContext.sol#L73-L78

Updated Code:

```solidity
function getBlockHashEVM(uint256 _block) external view returns (bytes32 hash) {
    require(_block <= block.number, "Block number is invalid");
    require(block.number - _block <= 256, "Block number is too far in the past");
    hash = blockHash[_block];
}
```
An attacker can manipulate the call stack of the transaction to impersonate another address and set a different value for the `origin` variable. 
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/SystemContext.sol#L60-L62


# Vulnerability details

## Impact
By changing the transaction's call stack, an attacker can use the origin variable to pretend to be another address, as a result, the attacker can be able to enter the system without authorization and carry out evil deeds.

## Proof of Concept
The vulnerability exists in the contract because it uses `tx.origin` to authorize users, which can be spoofed by a malicious contract that impersonates another address.
The line of code that uses `tx.origin` is:
https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/SystemContext.sol#L61

A possible exploit scenario is as follows:

* Alice owns a contract that uses `tx.origin` to authorize withdrawals of funds.
* Bob creates a malicious contract that calls Alice’s contract and passes his own address as the recipient of the withdrawal.
* Bob convinces Alice to interact with his contract, for example by offering some incentive or reward.
* Bob’s contract executes the withdrawal function on Alice’s contract using Alice’s `tx.origin` as the sender and Bob’s address as the recipient.
* Bob steals Alice’s funds without her consent or knowledge.

Proof-of-concept code for Bob's contract:
```solidity
contract Malicious {
    // The address of Alice's vulnerable contract
    address public target;

    // The address of Bob
    address public attacker;

    constructor(address _target) {
        target = _target;
        attacker = msg.sender;
    }

    // A function that lures Alice to interact with this contract
    function bait() public payable {
        // Some logic that entices Alice to call this function
        // For example, sending some ether or tokens to this contract
        // Or promising some reward or benefit for calling this function
    }

    // A fallback function that calls the withdraw function on Alice's contract
    fallback() external payable {
        // The amount to withdraw from Alice's contract
        uint256 amount = 1 ether;

        // The data to call the withdraw function on Alice's contract
        bytes memory data = abi.encodeWithSignature("withdraw(uint256,address)", amount, attacker);

        // Call the withdraw function on Alice's contract using low-level call
        (bool success,) = target.call(data);

        // Check if the call was successful
        require(success, "Call failed");
    }
}
```
As you can see, Bob sends `0` ether to his own contract, which then calls the withdraw function on Alice’s contract with `1` ether and Bob’s address as parameters. The transaction succeeds and Bob receives `1` ether from Alice’s contract.

## Tools Used
Manual audit

## Recommended Mitigation Steps
The contract should not rely on `tx.origin` to determine the sender of the transaction.
Instead, it should use `msg.sender`, which is the address that calle
L2EthToken contract integer overflow/underflow vulnerability
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/L2EthToken.sol#L54
https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/L2EthToken.sol#L40-L66
https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/L2EthToken.sol#L40-L76


# Vulnerability details

## Impact
If the amount of the sender or receiver is greater than or less than the maximum or minimum value of an `uint256`, the attacker may also result in a loss of cash, the `transferFromTo()` and `mint()` functions, which can only be invoked by trusted system contracts, are impacted by the issue.

## Proof of Concept
Integer overflow and underflow issues are disregarded using the unchecked keyword, the `balance[_to]` will overflow and wrap around to "0" if it exceeds the uint256's maximum value, which could allow an attacker to transfer more tokens than was intended.
The `balance[_to]` will similarly underflow and wrap around to the maximum value if it drops below the uint256's minimum value, which might allow an attacker to transfer a negative number of tokens.

A block that modifies the sender and recipient's balances in an uncontrolled manner is the source of the vulnerability in the `transferFromTo()` and `mint()` functions. Unexpected behavior may occur if the sender's or recipient's balance is greater than or less than the maximum or minimum value of an `uint256` due to an integer overflow or underflow.

By moving a large number of tokens from an account with a balance that is just below the maximum value of `uint256`, we can change the `transferFromTo()` function to simulate an integer overflow in order to show this issue.
https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/L2EthToken.sol#L40-L66

```solidity
function transferFromTo(address _from, address _to, uint256 _amount) external override {
    require(
        msg.sender == MSG_VALUE_SYSTEM_CONTRACT ||
            msg.sender == address(DEPLOYER_SYSTEM_CONTRACT) ||
            msg.sender == BOOTLOADER_FORMAL_ADDRESS,
        "Only system contracts with special access can call this method"
    );

    uint256 fromBalance = balance[_from];
    require(fromBalance >= _amount, "Transfer amount exceeds balance");
    unchecked {
        balance[_from] = fromBalance - _amount;
        balance[_to] += _amount;
    }

    emit Transfer(_from, _to, _amount);
}

// Attacker transfers a large amount of tokens from an account close to the maximum value of uint256
function attackTransfer() public {
    uint256 amount = 2 ** 255; // maximum value of uint256 is 2^256-1, so this value is close to the maximum
    transferFromTo(msg.sender, attacker, amount);
}
```
A significant number of tokens are transferred from an account with a balance that is almost as high as the maximum value of "uint256" in this modified function by an attacker, an int
Reentrancy Attack on mimicCall Function
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/MsgValueSimulator.sol#L62


# Vulnerability details

## Impact
Could be used by an attacker to carry out a reentrancy attack on the contract, the attacker might then be able to make several calls to the contract in a single transaction, which could lead to the loss of money or undesired behavior.

## Proof of Concept
Let's assume the following situation to illustrate the reentrancy vulnerability:

* There is a contract `MaliciousContract` that has a fallback function.
* `MsgValueSimulator` contract is calling `MaliciousContract` in its fallback function through mimicCall`.
* `MaliciousContract` calls back to `MsgValueSimulator` in its fallback function, before the `mimicCall` function finishes executing.

Illustration of how the reentrancy vulnerability is exploited by the `MaliciousContract` contract:
```solidity
contract MaliciousContract {
    address private _msgValueSimulator;

    constructor(address msgValueSimulator) {
        _msgValueSimulator = msgValueSimulator;
    }

    fallback() external payable {
        // Reentrancy attack
        (bool success, ) = _msgValueSimulator.call(abi.encodeWithSignature("fallback(bytes)", msg.data));
        require(success);
    }
}
```
In this case, the fallback function of `MaliciousContract` calls the fallback function of `_msgValueSimulator`, which can then call back `MaliciousContract` before it updates its balance1.

In the constructor of `MaliciousContract`, i store the address of `MsgValueSimulator, In the fallback function of MaliciousContract, then call `MsgValueSimulator` using the stored address and pass along the `msg.data`.
This causes `MsgValueSimulator` to call back to `MaliciousContract`, which in turn calls back to `MsgValueSimulator`, and so on, creating an infinite loop.


## Tools Used

## Recommended Mitigation Steps
The checks-effects-interactions design pattern, where checks come first, then effects, and then interactions, can be used with `MsgValueSimulator`, In this instance, the interaction is the `mimicCall`, and the results are the transfer of ETH and changing the `msg.value` for the subsequent call. We can guarantee that the state is not changed if the checks are unsuccessful by conducting the checks before to the effects, thwarting the reentrancy attack.

Implementing this pattern.

```solidity
fallback(bytes calldata _data) external payable onlySystemCall returns (bytes memory) {
    (uint256 value, bool isSystemCall, address to) = _getAbiParams();

    // Check if the contract has already been called
    require(!_currentlyExecuting);

    // Set the flag to true to prevent reentrancy attack
    _currentlyExecuting = true;

    if (value != 0) {
        (bool success, ) = address(ETH_TOKEN_SYSTEM_CONTRACT).call(
            abi.encodeCall(ETH_TOKEN_SYSTEM_CONTRACT.transferFromTo, (msg.sender, to, value))
        );

        // If the transfer of ETH f