xanoutas/solidity-security-findings huggingface dataset:
No sanity check on `_l1Token` can lead into a bad deployment on the bridge
Audit: 2022-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-10-zksync/blob/5a31c9db8ab32175dbd7264b05ce84931b6c0428/zksync/contracts/bridge/L2ERC20Bridge.sol#L77


# Vulnerability details

# No checks on `_l1Token` can lead into a bad deployment on the bridge
### Impact 
`_deployL2Token` calls `bridgeInitialize` which is only callable one time for token as it uses `initializer` modifier. 

There are no checks for 0 address which can be assigned by error as it is a default value, if 0 address is assigned it can lead to unexpected behaviors on the bridge.

### Github permalinks
https://github.com/code-423n4/2022-10-zksync/blob/5a31c9db8ab32175dbd7264b05ce84931b6c0428/zksync/contracts/bridge/L2ERC20Bridge.sol#L77
        L2StandardERC20(address(l2Token)).bridgeInitialize(_l1Token, _data);

### Mitigation
- Add 0 check for the `_l1Token` address before initializing the bridge
Potential DoS in unbounded for loop
Audit: 2022-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-10-zksync/blob/5a31c9db8ab32175dbd7264b05ce84931b6c0428/ethereum/contracts/zksync/facets/Getters.sol#L163


# Vulnerability details

### Proof of Concept

The function `facets()` in `Getters.sol` iterates over the `DiamondStorage` `facets` array. In `Diamond.sol` we can see that by calling `diamondCut` in a way that  `_saveFacetIfNew` gets called, the diamond owner can add an indefinite amount of entries. If this is the case, the `facets()` function will be in a state of DoS because iterating over a very big array can cost more than the current block gas limit. 

### Impact

The impact is potential functionality getting into a DoS state which is a problem even though the method is a getter - it might be used in a front-end.

### Recommendation

Add an `offset` parameter to the `facets()` function so the loop iterates the array starting from `offset` index
No commitment to data passed as input to the init contract during the execution of the diamond cut proposal
Audit: 2022-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/facets/DiamondCut.sol#L46
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/facets/DiamondCut.sol#L61
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/Diamond.sol#L92
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/Diamond.sol#L113
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/Diamond.sol#L282


# Vulnerability details

## Description

There is a function `executeDiamondCutProposal` in the `DiamondCutFacet` contract. It checks that proposal data passed as input to this call is equal to the data that is declared when the creation of this proposal using the following logic:

```solidity=
require(
    s.diamondCutStorage.proposedDiamondCutHash ==
        keccak256(abi.encode(_diamondCut.facetCuts, _diamondCut.initAddress)),
    "a4"
); // proposal should be created
```

But there are no checks on data that is used as input to the init contract during the execution of the diamond cut proposal.

Although such functionality may be in demand for the cases when part of the input data will be known only at the stage of execution of the proposal, in most cases init input data will be known at the stage of creation of the proposal, so it will be better to include such data to the proposal hash preimage. It will prevent a user from malicious input data that can be passed when executing the proposal and even from malicious input data that can be passed by an attacker through a potential leak of the governance private key (in the case when the governance private key was stolen attacker will not have an ability to maliciously run a fast upgrade and stole assets due to notice period, but in the case when trusted governance initiated the proposal, an attacker will have the ability to execute it with malicious init contract's input data).

## Recommended Mitigation Steps

Use a combination of the data that is expected to be known at the stage of creation of the proposal (including such data as a part of the proposal hash preimage) with the data that is expected to be known only at the stage of the execution of the proposal.
`uint16` type for the facet position and selector position
Audit: 2022-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/Diamond.sol#L24
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/Diamond.sol#L33
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/Diamond.sol#L190
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/Diamond.sol#L207


# Vulnerability details

## Description

In the `Diamond` library there is `uint16` type used for the facet position and selector position in the `FacetToSelectors` and `SelectorToFacet` structs. That creates a restriction that the number of facets is limited by `2^16`.

In case when the number of facets is greater or equal to `2^16` there will be different facets with an equal value of `facetPosition` parameter (there will be unchecked overflow in `ds.facetToSelectors[_facet].facetPosition = uint16(ds.facets.length);`). The same applies to the `selectorPosition` parameter.

## Recommended Mitigation Steps

For the facet position and selector position use a type with a bigger number of possible values, for example `uint32` or even `uint256`.
No Checks On Withdraw Function For _amount
Audit: 2022-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-10-zksync/blob/main/zksync/contracts/bridge/L2ETHBridge.sol#L66


# Vulnerability details

## Impact
If bridgeburn function is a faulty function or a contract that uses older version of solidity the variable the balance may overflow due to lack of checks.

## Proof of Concept
In the function https://github.com/code-423n4/2022-10-zksync/blob/main/zksync/contracts/bridge/L2ETHBridge.sol#L66 there should be a check `balanceOf[msg.sender]>=_amount` to mitigate unwanted reverts or overflow in extreme edge cases

## Tools Used
Manual Analysis

## Recommended Mitigation Steps
Add the check mentioned
Mssing Crucial Checks When Unlocking funds for Withdraw Requests from L2
Audit: 2022-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/bridge/L1ERC20Bridge.sol#L254
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/bridge/L1EthBridge.sol#L208


# Vulnerability details

## Impact
Atomicity literally does not exist when users from L2 initiate a withdrawal by burning funds on the contract and sending the message to L1. This is giving malicious attackers plenty of time to stealthily launch a series of small and yet sizable forgery of transactions that could fool the tree of assertions, allowing validators to pipeline execution by continuing to build the tree even before all nodes are confirmed via low level proof just like what recently happened to the BNB bridge on [Oct 6, 2022](https://rekt.news/bnb-bridge-rekt/).

## Proof of Concept
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/bridge/L1ERC20Bridge.sol#L254

```
254        IERC20(l1Token).safeTransfer(l1Receiver, amount);
```
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/bridge/L1EthBridge.sol#L208

```
208        _withdrawFunds(l1Receiver, amount);
```
The critical issue lies correspondingly on line 254 of `L1ERC20Bridge.sol` and line 208 of `L1EthBridge.so` being devoid of at least a contract balance check prior to transferring funds to `l1Receiver`. Even so, something would be very wrong if `amount <= IERC20(l1Token).balanceOf(address(this))` or `amount <= address(this).balance` ever reverted. All funds in the contract for the associated token or ETH would have been drained when this had happened, presumably due to the undetected malicious acts from the attackers.

## Tools Used
Manual inspection and read up

## Recommended Mitigation Steps
Consider refactoring the codes that would have the malicious attacks detected at the earliest possibility. To the least, an internal function that could validate the tally of L2 burn and L1 escrow release (using OpenZeppelin's ECDSA for instance) should be embedded before the contract balance require check. Have an instant trigger mechanism to pause/freeze the affected contract/function if suspicious activity, e.g. a sudden drop in contract balance, is detected.
Unsafe Initializations Of Bridge Contracts
Audit: 2022-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/bridge/L1ERC20Bridge.sol#L71-L103
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/bridge/L1EthBridge.sol#L56-L80


# Vulnerability details

## Vulnerability Details

During the zkSync initialization process, several complicated tasks would be required to execute. Incorrect configurations in some tasks could lead to unexpected vulnerabilities.

One task of the zkSync initialization process is deploying and initializing the `L1ERC20Bridge` and `L1EthBridge` contracts.

**We detected that the process of initializing the `L1ERC20Bridge` and `L1EthBridge` contracts was implemented unsafely, which could lead to potential attacks on assets and dApps (Decentralized Applications) on the L2 network.**

To elaborate on the issue, the `initialize` functions of the contracts `L1ERC20Bridge` (code snippet 1) and `L1EthBridge` (code snippet 2) must be triggered to set up the bridge contracts and other related subsystems.

**The `initialize` functions would be left uninitialized for a short period after the `L1ERC20Bridge` and `L1EthBridge` contracts were deployed. Nevertheless, we considered that the short period in question is enough to open room for an attacker to perform front-running attacks to be the successful executor of the `initialize` functions**.

**As a result, the attacker can deploy the malicious implementations of the `L2ERC20Bridge` and `L2EthBridge` contracts and then begin another attack steps to exploit assets and dApps on the L2 network.**

**The root cause is that the `initialize` functions of the contracts `L1ERC20Bridge` (code snippet 1) and `L1EthBridge` (code snippet 2) lack a proper access control mechanism.** In other words, the `initialize` functions with no access restriction allow any unauthorized user to execute them.

Even though the likelihood of this issue would be low, its impact could be high. Thus, we considered this issue medium severity.

```solidity
SNIPPET: 1
FILE: https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/bridge/L1ERC20Bridge.sol

71:     function initialize(
72:         bytes[] calldata _factoryDeps,
73:         address _l2TokenFactory,
74:         address _governor
75:     ) external reentrancyGuardInitializer {
76:         // We are expecting to see the exect two bytecodes that are needed to initiailize the bridge
77:         require(_factoryDeps.length == 2, "mk");
78:         l2ProxyTokenBytecodeHash = L2ContractHelper.hashL2Bytecode(_factoryDeps[1]);
79:         l2TokenFactory = _l2TokenFactory;
80: 
81:         bytes32 create2Salt = bytes32(0);
82:         bytes memory create2Input = abi.encode(address(this), l2ProxyTokenBytecodeHash, _governor);
83:         bytes32 l2BridgeBytecodeHash = L2ContractHelper.hashL2Bytecode(_factoryDeps[0]);
84:         bytes memory deployL2BridgeCalldata = abi.encodeCall(
85:             IContractDeployer.create2,
86:             (creat
WHEN EVER CALLING bridgeMint OR bridgeBurn FUNCTIONS NEED TO CHECK THE STATUS OF THE TRANSACTIONS
Audit: 2022-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/zksync/contracts/bridge/L2ERC20Bridge.sol#L92
https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/zksync/contracts/bridge/L2ERC20Bridge.sol#L67


# Vulnerability details

## Impact
If not checking the status of the  bridgeMint and bridgeBurn  functions we don't know the the transactions are success or not. If function breaks any of the reasons we don't what happened and what is the status of the transactions.

there is no solutions provided if any bridgeMint or bridgeBurn functions failures. 

## Proof of Concept

 IL2StandardToken(expectedL2Token).bridgeMint(_l2Receiver, _amount);

 IL2StandardToken(_l2Token).bridgeBurn(msg.sender, _amount);

## Tools Used

Manual Finding

## Recommended Mitigation Steps

We can use require statements to check the status of the functions . If any failures occurs it will throws the error message .
1) THERE IS CONFLICT IN REQUIRE STATMENT. IN finalizeDeposit FUNCTION CHECKS require (msg.sender == l1Bridge, "mq"). IN bridgeMint FUNCTION IMPLEMENTATIONS onlyBridge Modifier CHECKS  require(msg.sender == l2Bridge). 
Audit: 2022-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/zksync/contracts/bridge/L2ERC20Bridge.sol#L58-L67
https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/zksync/contracts/bridge/L2StandardERC20.sol#L95


# Vulnerability details

1) 

## Impact
Let assume if we calling bridgeMint() from finalizeDeposit function the msg.sender is l1bridge . if the msg.sender is not l1bridge can't run the finalizeDeposit 

but as per bridgeMint() the msg.sender should be l2bridge. So it will cause the conflict . the bridgeMint() always fails since the caller function msg.sender is l1bridge.

modifier onlyBridge() {
        require(msg.sender == l2Bridge);
        _;
    }

function bridgeMint(address _to, uint256 _amount) external override onlyBridge {
        _mint(_to, _amount);
        emit BridgeMint(_to, _amount);
    }

PROOF OF CONCEPT

https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/zksync/contracts/bridge/L2ERC20Bridge.sol#L58-L67

https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/zksync/contracts/bridge/L2StandardERC20.sol#L95-L105

TOOLS :  Manual Finding

 Recommended Mitigation Steps

We need to change the require statement conditions which is suitable for both scenarios.
_safeMint should be used to work with smart contract address
Audit: 2022-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/zksync/contracts/bridge/L2StandardERC20.sol#L103


# Vulnerability details

## Fix
_safeMint() should be used if you are sending the minted token to a Contract that is capable to manage NFTs or not. This is to prevent tokens to be lost.

## Recommended Mitigation Steps
Replace `_mint` with `_safeMint`.

## Tools Used
Manual review
Not possible to DiamondCut in frozen status
Audit: 2022-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/ethereum/contracts/zksync/facets/DiamondCut.sol#L46-L75


# Vulnerability details

## Impact
DiamondCut's `executeDiamondCutProposal` executes the proposed `_diamondCut` calldata in the Diamond is unfrozen condition.
However, if there are any possible situations that require restriction implementation in which the upgrade should be executed in a frozen Diamond, this will not be possible.

## Proof of Concept
```solidity
    function executeDiamondCutProposal(Diamond.DiamondCutData calldata _diamondCut) external onlyGovernor {
        Diamond.DiamondStorage storage diamondStorage = Diamond.getDiamondStorage();


        bool approvedBySecurityCouncil = s.diamondCutStorage.securityCouncilEmergencyApprovals >=
            SECURITY_COUNCIL_APPROVALS_FOR_EMERGENCY_UPGRADE;


        bool upgradeNoticePeriodPassed = block.timestamp >=
            s.diamondCutStorage.proposedDiamondCutTimestamp + UPGRADE_NOTICE_PERIOD;


        require(approvedBySecurityCouncil || upgradeNoticePeriodPassed, "a6"); // notice period should expire
        require(approvedBySecurityCouncil || !diamondStorage.isFrozen, "f3");
        // should not be frozen or should have enough security council approvals


        require(
            s.diamondCutStorage.proposedDiamondCutHash ==
                keccak256(abi.encode(_diamondCut.facetCuts, _diamondCut.initAddress)),
            "a4"
        ); // proposal should be created


        require(_resetProposal(), "a5"); // failed reset proposal


        if (diamondStorage.isFrozen) {
            diamondStorage.isFrozen = false;
            emit Unfreeze(s.diamondCutStorage.lastDiamondFreezeTimestamp);
        }


        Diamond.diamondCut(_diamondCut);


        emit DiamondCutProposalExecution(_diamondCut);
    }
```
[Permalink](https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/ethereum/contracts/zksync/facets/DiamondCut.sol#L46-L75)

## Tools Used
Manual review
## Recommended Mitigation Steps
The team might consider unfreezing the diamond after the cut;
```solidity
Diamond.diamondCut(_diamondCut);

if (diamondStorage.isFrozen) {
    diamondStorage.isFrozen = false;
    emit Unfreeze(s.diamondCutStorage.lastDiamondFreezeTimestamp);
}
```
L1ERC20Bridge does not have an emergency stop mechanism to pause the bridge in case of any problems found.
Audit: 2022-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/ethereum/contracts/bridge/L1ERC20Bridge.sol#L115
https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/ethereum/contracts/bridge/L1ERC20Bridge.sol#L187
https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/ethereum/contracts/bridge/L1ERC20Bridge.sol#L231


# Vulnerability details

## Impact

Right now, L1ERC20Bridge implements nonReentrant and access control mechanism to improve security. However, there is not any emergency stop mechanism that can be triggered by an authorized account to pause the bridge in case of some problems. It is highly suggested to implement this kind of mechanism which will ensure the bridge can be paused to reduce possible damage.

## Proof of Concept

https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/ethereum/contracts/bridge/L1ERC20Bridge.sol#L115

https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/ethereum/contracts/bridge/L1ERC20Bridge.sol#L1187

https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/ethereum/contracts/bridge/L1ERC20Bridge.sol#L231
## Tools Used

## Recommended Mitigation Steps

It is suggested to use Pausable contract module from openzeppelin in L1ERC20Bridge.sol. This module can be used through inheritance. It will make available the modifiers whenNotPaused, which can be applied to the functions of deposit(), claimFailedDeposit() and finalizeWithdrawal() in L1ERC20Bridge.sol
`BLOCK_PERIOD` is incorrect
Audit: 2022-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/ethereum/contracts/zksync/Config.sol#L47


# Vulnerability details

The `BLOCK_PERIOD` is set to 13 seconds in `Config.sol`.
```sol
uint256 constant BLOCK_PERIOD = 13 seconds;
```
Since moving to Proof-of-Stake (PoS) after the Merge, block times on ethereum are fixed at 12 seconds per block (slots).
https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/#:~:text=Whereas%20under%20proof%2Dof%2Dwork,block%20proposer%20in%20every%20slot.

### Impact
This results in incorrect calculation of `PRIORITY_EXPIRATION` which is used to determine when a transaction in the Priority Queue should be considered expired.

```sol
uint256 constant PRIORITY_EXPIRATION_PERIOD = 3 days;
/// @dev Expiration delta for priority request to be satisfied (in ETH blocks)
uint256 constant PRIORITY_EXPIRATION = PRIORITY_EXPIRATION_PERIOD/BLOCK_PERIOD;
```
The time difference can be calulated
```python
>>> 3*24*60*60 / 13    # 3 days / 13 sec block period
19938.46153846154
>>> 3*24*60*60 / 12    # 3 days / 12 sec block period
21600.0
>>> 21600 - 19938      # difference in blocks
1662
>>> 1662 * 12 / (60 * 60) # difference in hours
5.54
```
By using block time of 13 seconds, a transaction in the Priority Queue incorrectly expires 5.5 hours earlier than is expected.

5.5 hours is a significant amount of time difference so I believe this issue to be Medium severity.

### Recommendations
Change the block period to be 12 seconds
```sol
uint256 constant BLOCK_PERIOD = 12 seconds;
```
Validator can revert block at no cost.
Audit: 2022-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/ethereum/contracts/zksync/facets/Executor.sol#L336


# Vulnerability details

## Impact

Validator can revert block at no cost.

## Proof of Concept

the validator should only call this function on Executor.sol to revert the unexecuted blocks if the block is not really not executable.

```solidity
/// @notice Reverts unexecuted blocks
/// @param _newLastBlock block number after which blocks should be reverted
/// NOTE: Doesn't delete the stored data about blocks, but only decreases
/// counters that are responsible for the number of blocks
function revertBlocks(uint256 _newLastBlock) external nonReentrant onlyValidator {
	require(s.totalBlocksCommitted > _newLastBlock, "v1"); // the last committed block is less new last block
	uint256 newTotalBlocksCommitted = _maxU256(_newLastBlock, s.totalBlocksExecuted);

	if (newTotalBlocksCommitted < s.totalBlocksVerified) {
		s.totalBlocksVerified = newTotalBlocksCommitted;
	}
	s.totalBlocksCommitted = newTotalBlocksCommitted;

	emit BlocksRevert(s.totalBlocksCommitted, s.totalBlocksVerified, s.totalBlocksExecuted);
}
```

However, a dishonest validator can just call this function to revert valid executable block at no cost.

## Tools Used

Manual Review

## Recommended Mitigation Steps

The cost for dishonest validator is minimum, even nothing. The worst things is the validator is removed as validator, but the project still need to spend resources to remedy
the damage left by validators. I think if the team let validator stake token and slash the token reward if the validator misbehave, that would contain validator's dishonest behavior.