xanoutas/solidity-security-findings huggingface dataset:
The function "ContractDeployer.updateNonceOrdering" is restricted in its ability to modify something other than the "Arbitrary" option.
Audit: 2023-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-03-zksync/blob/main/contracts/ContractDeployer.sol#L66-L82


# Vulnerability details

## Impact
The function "ContractDeployer.updateNonceOrdering" is restricted in its ability to modify something other than the "Arbitrary" option

## Proof of Concept
The code in "ContractDeployer.sol" from lines 66 to 82 is about a function called "updateNonceOrdering." This function currently allows only one specific parameter, "AccountNonceOrdering.Arbitrary," to be used. Given this limitation, the function can be secured better

The original function:
```solidity
function updateNonceOrdering(AccountNonceOrdering _nonceOrdering) external onlySystemCall {
    AccountInfo memory currentInfo = _accountInfo[msg.sender];

    require(
        _nonceOrdering == AccountNonceOrdering.Arbitrary &&
            currentInfo.nonceOrdering == AccountNonceOrdering.Sequential,
        "It is only possible to change from sequential to arbitrary ordering"
    );
    // Rest of the function logic
}
```

```
  /// @notice Updates the nonce ordering of the account. Currently,
    /// it only allows changes from sequential to arbitrary ordering.
    /// @param _nonceOrdering The new nonce ordering to use.
    function updateNonceOrdering(AccountNonceOrdering _nonceOrdering) external onlySystemCall {
        AccountInfo memory currentInfo = _accountInfo[msg.sender];

        require(
            _nonceOrdering == AccountNonceOrdering.Arbitrary &&
                currentInfo.nonceOrdering == AccountNonceOrdering.Sequential,
            "It is only possible to change from sequential to arbitrary ordering"
        );

        currentInfo.nonceOrdering = _nonceOrdering;
        _storeAccountInfo(msg.sender, currentInfo);

        emit AccountNonceOrderingUpdated(msg.sender, _nonceOrdering);
    }
```


## Tools Used
Manual / VsCode

## Recommended Mitigation Steps
The refactored function:
```solidity
function setToArbitraryNonceOrdering() external onlySystemCall {
    _accountInfo[msg.sender].nonceOrdering = AccountNonceOrdering.Arbitrary;
    emit AccountNonceOrderingUpdated(msg.sender, _nonceOrdering);
}
```

In the refactored version, the function is renamed to "setToArbitraryNonceOrdering," and it now directly changes the nonce ordering to "Arbitrary" without needing the previous checks. This simplified function is more intuitive and easier to understand.



## Assessed type

Context
Few tests for Verifier.sol
Audit: 2023-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/test/unit_tests/verifier.spec.ts#L7


# Vulnerability details

## Impact
The main proof verification system is a complex part of the code. There is not enough testing done on it to ensure it functions properly without any bugs.

## Proof of Concept
https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/test/unit_tests/verifier.spec.ts#L7

Nearly all of the testing found for verifier.sol is done here. It includes a only a few different test cases for the main verification function. 

Given the criticality of the main verifier.sol to the functionality of the ZK system it is recommended to perform more rigorous testing to it.

## Recommended Mitigation Steps
Add tests for the 5 or 6 subfunctions of the verifier.sol library to ensure they perform correctly in addition to the main verification logic.


## Assessed type

Other
NonceHolder.incrementDeploymentNonce has redundant access control check
Audit: 2023-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-03-zksync/blob/main/contracts/NonceHolder.sol#L134-L135


# Vulnerability details

## Impact
The code in "NonceHolder.sol" at lines 134-135 defines a function called "incrementDeploymentNonce." This function is marked as "external" and includes the "onlySystemCall" modifier. It verifies that the caller of this function is the "DEPLOYER_SYSTEM_CONTRACT" before proceeding with its logic

## Proof of Concept
The onlySystemCall modifier can be removed since only the DEPLOYER_SYSTEM_CONTRACT can call this function anyway. It is an unnecessary redundant check. It would also be good to add an error message like "only Deployer system contract can increment deployment nonce".

```
    function incrementDeploymentNonce(address _address) external onlySystemCall returns (uint256 prevDeploymentNonce) {
        require(msg.sender == address(DEPLOYER_SYSTEM_CONTRACT), "");
```

The code in "NonceHolder.sol" at lines 134-135 defines a function called "incrementDeploymentNonce." This function is marked as "external" and includes the "onlySystemCall" modifier. It verifies that the caller of this function is the "DEPLOYER_SYSTEM_CONTRACT" before proceeding with its logic

## Tools Used
Manual

## Recommended Mitigation Steps
However, it can be improved as follows:

Removing the "onlySystemCall" Modifier: The "onlySystemCall" modifier is redundant in this context. This is because the "require" statement immediately checks if the caller is the "DEPLOYER_SYSTEM_CONTRACT" using the "msg.sender" comparison. Since this requirement already enforces the intended access control, the modifier becomes superfluous.

Adding a Descriptive Error Message: It's considered good practice to include a clear error message in the "require" statement to explain why the condition must be met. In this case, the error message could be something like "only DEPLOYER system contract can increment deployment nonce." This provides a meaningful explanation to anyone who encounters the error.


## Assessed type

Access Control
Missing Re-entrancy protection
Audit: 2023-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/zksync/contracts/bridge/L2Weth.sol#L87-L90
https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/zksync/contracts/bridge/L2Weth.sol#L93-L95
https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/zksync/contracts/bridge/L2Weth.sol#L98-L100
https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/zksync/contracts/bridge/L2Weth.sol#L104-L108
https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/zksync/contracts/bridge/L2Weth.sol#L111-L113


# Vulnerability details

## Impact

All functions mentioned below are susceptible to re-entrancy, deposit, withdraw, depositTo, withdawTo... 

Although reentrancy attack is considered quite old over the past two years, there have been cases such as:

Uniswap/LendfMe hacks (2020) ($25 mln, attacked by a hacker using a reentrancy)

The BurgerSwap hack (May 2021) ( $7.2 million because of a fake token contract and a reentrancy exploit.)

The SURGEBNB hack (August 2021) ($4 million seems to be a reentrancy-based price manipulation attack.)

CREAM FINANCE hack (August 2021) ($18.8 million, reentrancy vulnerability allowed the exploiter for the second borrow.)

Siren protocol hack (September 2021) ($3.5 million, AMM pools were exploited through reentrancy attack.)

## Proof of Concept
    /// @notice Deposit Ether to mint WETH.
    function deposit() external payable override {
        depositTo(msg.sender);
    }

    /// @notice Withdraw WETH to get Ether.
    function withdraw(uint256 _amount) external override {
        withdrawTo(msg.sender, _amount);
    }

    /// @notice Deposit Ether to mint WETH to a given account.
    function depositTo(address _to) public payable override {
        _mint(_to, msg.value);
    }

    /// @notice Withdraw WETH to get Ether to a given account.
    /// burns sender's tokens and sends Ether to the given account
    function withdrawTo(address _to, uint256 _amount) public override {
        _burn(msg.sender, _amount);
        (bool success, ) = _to.call{value: _amount}("");
        require(success, "Failed withdrawal");
    }

    /// @dev Fallback function to allow receiving Ether.
    receive() external payable {
        depositTo(msg.sender);
    }

https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/zksync/contracts/bridge/L2Weth.sol#L87C1-L113C6

## Recommended Mitigation Steps

Use Openzeppelin or Solmate Re-Entrancy pattern.


    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.13;

    contract ReEntrancyGuard {
        bool internal locked;

    modifier noReentrant() {
        require(!locked, "No re-entrancy");
        locked = true;
        _;
        locked = false;
    }
}



## Asses
Multiple Values for Same Proof 
Audit: 2023-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/contracts/zksync/Verifier.sol#L493


# Vulnerability details

## Impact
There is an additional malleability coming from proofs because of the choice to allow wrapping components around modulo Q and modulo R. 

If any application uses / stores calldata from the verified proofs, it is vulnerable to manipulation / proof replaying because of this malleability.

## Proof of Concept
The developers choose to allow inputs larger than the moduli Q_MOD, R_MOD without reverting:
https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/contracts/zksync/Verifier.sol#L493

This allows multiple identical proofs for almost every different input:
https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/contracts/zksync/Verifier.sol#L532

This could be dangerous when combined with another vulnerability. See, for example, the Semaphore vulnerability:
https://medium.com/@Beosin_com/an-in-depth-analysis-of-zk-snark-input-aliasing-vulnerability-d9b80f50dce6


## Recommended Mitigation Steps
Ensure that the inputs are less than the respective modulus, Q_MOD or R_MOD.


## Assessed type

Other
Owner cannot execute operation if in `Waiting` state
Audit: 2023-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/contracts/governance/Governance.sol#L94-L97
https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/contracts/governance/Governance.sol#L167-L181


# Vulnerability details

## Impact
Owner cannot execute operation if in `Waiting` state which contradicts one of the comments

https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/contracts/governance/Governance.sol#L94-L97
```solidity
File: /code/contracts/ethereum/contracts/governance/Governance.sol
94:    /// @dev Returns whether an operation is ready for execution. Note that a "ready" operation is also "pending".
95:    function isOperationReady(bytes32 _id) public view returns (bool) {
96:        return getOperationState(_id) == OperationState.Ready;
97:    }
```
From the comment above, we see that a `ready` operation is also `pending`, however, when checking the state, we are only checking for the `ready` state.
As a result of the above, the following function would not execute if the operation happens to be in the `Waiting/Pending` state
Calling `require(isOperationReady(id), "Operation must be ready before execution");` would fail if our operation is in `Pending` state since our function `isOperationReady()` only checks for `ready` state

https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/contracts/governance/Governance.sol#L167-L181
```solidity
167:    function execute(Operation calldata _operation) external onlyOwnerOrSecurityCouncil {
168:        bytes32 id = hashOperation(_operation);
169:        // Check if the predecessor operation is completed.
170:        _checkPredecessorDone(_operation.predecessor);
171:        // Ensure that the operation is ready to proceed.
172:        require(isOperationReady(id), "Operation must be ready before execution");
173:        // Execute operation.
174:        _execute(_operation.calls);
175:        // Reconfirming that the operation is still ready after execution.
176:        // This is needed to avoid unexpected reentrancy attacks of re-executing the same operation.
177:        require(isOperationReady(id), "Operation must be ready after execution");
178:        // Set operation to be done
179:        timestamps[id] = EXECUTED_PROPOSAL_TIMESTAMP;
180:        emit OperationExecuted(id);
181:    }
```

## Tools Used
Manual Review
## Recommendation
The function `isOperationReady()` should also check for the `waiting/Pending` state if the comment is correct, else the comment is misleading

```diff
     function isOperationReady(bytes32 _id) public view returns (bool) {
-        return getOperationState(_id) == OperationState.Ready;
+        OperationState state = getOperationState(_id);
+        return state == OperationState.Ready || state ==
Goldilocks should never be used for elliptic curve pairing verification
Audit: 2023-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/docs/Circuits%20Section/Boojum%20gadgets.md?plain=1#L3


# Vulnerability details


##Impact

The Goldilocks field is unsafe for performing verification, since the discrete logarithm is easy to perform over it.

##Proof of Concept

The goldilocks field is used as the basis for ZKevm computations, but as far I see, never for any type of verification.

This should be made explicit in the documents to avoid anyone implementing cryptographic / verificaiton algorithms over that field.

The bit strength of Goldilocks is only ~64 bits, and even the extension fields for pairing is only 128 bits
https://blog.icme.io/small-fields-for-zero-knowledge/

So performing a pairing over this field is unsafe, as computers can solve discrete logarithm over 128 bit extension fields.

##Recommendation
Make explicit in the documents that Goldilocks should not be used for EC verification / pairing. Make sure to use it only for computations in the VM, and not for secrets and other cryptography.


## Assessed type

Other
There is a lack of documentation explaining the packing process for the `ZkSyncMeta` structure.
Audit: 2023-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-03-zksync/blob/main/contracts/libraries/SystemContractsCaller.sol#L41-L46
https://github.com/matter-labs/era-zkevm_opcode_defs/blob/main/src/definitions/abi/meta.rs#L14


# Vulnerability details

## Impact
The documentation does not provide any details about how the ZKSyncMeta structure is packed and encoded. While there is a reference to the Rust code in the README that demonstrates this process, it may not be useful for future developers who are not familiar with Rust.

## Proof of Concept
This concern relates to the lack of clarity in the codebase's documentation regarding how the `ZKSyncMeta` struct is structured, packed, and encoded. In the README file, there is a reference to Rust code that provides insights into the packing process of `ZKSyncMeta`. However, this reference may not be particularly useful to developers and auditors who are not well-versed in the Rust programming language.

```
// All the offsets are in bits
uint256 constant META_GAS_PER_PUBDATA_BYTE_OFFSET = 0 * 8;
uint256 constant META_HEAP_SIZE_OFFSET = 8 * 8;
uint256 constant META_AUX_HEAP_SIZE_OFFSET = 12 * 8;
uint256 constant META_SHARD_ID_OFFSET = 28 * 8;
uint256 constant META_CALLER_SHARD_ID_OFFSET = 29 * 8;
uint256 constant META_CODE_SHARD_ID_OFFSET = 30 * 8;

```

```
   pub const fn to_u256(self) -> U256 {
```

The suggestion is to include informative comments directly within the code, placed right above the offset constants used for packing and encoding the `ZKSyncMeta` structure. These comments would serve as essential documentation, explaining how the various components of `ZKSyncMeta` are packed and encoded. This guidance would make it much easier for all developers and auditors, regardless of their familiarity with Rust, to understand how the packing and encoding process works.

By offering this level of detail within the codebase, the development team can significantly improve the accessibility of the code for anyone reviewing it. It ensures that those examining the code can quickly grasp how the functions responsible for extracting different fields from `ZKSyncMeta` are functioning, which is crucial for auditing and verifying the code's correctness and security. In summary, this recommendation seeks to enhance transparency and facilitate the auditing process by providing explicit and accessible documentation within the codebase.
## Tools Used
Manual 

## Recommended Mitigation Steps
 To address this, it is recommended to include comments right above the offset constants in the code, explaining the packing and encoding of ZKSyncMeta. These comments would serve as a valuable reference for all developers and auditors, making it easier for them to verify that the functions responsible for extracting different fields from ZKSyncMeta are functioning correctly as intended. This additional documentation can enhance the overall understanding of the codebase and facilitate the auditing process.


## Assessed type

Oth
Admin.setValidator() should require Security Council approval or timelock delay
Audit: 2023-10-zksync-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/contracts/zksync/facets/Admin.sol#L65-L71


# Vulnerability details

## Summary
The `Admin.setValidator()` function’s access control is too permissive since it allows the admin account to (immediately and unilaterally) change the validator / operator. 

## Vulnerability Details
The security council (SC) is supposed to serve as a safety check on the powers of the admin account to greatly reduce the risk of malicious action or mistake by it. But, because the `Admin.setValidator()` function has the `onlyGovernorOrAdmin` access control modifier, the admin account can change the whitelisted validator address(es) without approval of the SC nor with any timelock to allow for a review period.

While the project documentation says that the admin account can make "*non-critical changes to the system such as granting validator permissions*", this power should not be considered “non-critical”. In the current implementation, the validator entity is synonymous with “operator” as they are both functions of the same zkSync node software. The operator is not fully trusted according to the audit readme: "*Special scrutiny should be paid to the powers of the operator … it should never be able to directly steal users' funds or conduct malicious upgrades*”. So, the ability to replace the operator is a security-critical power that necessitates a timelock or approval by the Security Council. Private discussion with the sponsor team has confirmed this.

## Impact
The operator implementation can be changed without Security Council approval nor any timelock delay for review. A mistake could be easily reverted once known, but the greatest risk is unknowingly introducing a new vulnerability that is not detected due to lack of review. Malicious action by the admin account is also a possibility as evidenced by the existence of the SC to check its actions. 

## Proof of Concept
n/a

## Tools Used
Manual Review

## Recommended Mitigation Steps
`Admin.setValidator()` should use the `onlyGovernor` modifier (rather than `onlyGovernorOrAdmin`) so that it can only be called by the Governor.sol contract.


## Assessed type

Access Control
SystemContractHelper.getZkSyncMeta does not include heapSize and auxHeapSize
Audit: 2023-10-zksync-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
The getZkSyncMeta function in SystemContractHelper is missing two important fields, heapSize and auxHeapSize, within the ZkSyncMeta struct. These fields are crucial for the proper functioning of the system, but the current implementation does not include them. 

## Proof of Concept
In the code, there is a struct named `ZkSyncMeta` that is meant to store several pieces of information. The struct includes fields like `gasPerPubdataByte`, `heapSize`, `auxHeapSize`, `shardId`, `callerShardId`, and `codeShardId`. These fields are essential for managing and executing operations within the system.

```
struct ZkSyncMeta {
    uint32 gasPerPubdataByte;
    uint32 heapSize;
    uint32 auxHeapSize;
    uint8 shardId;
    uint8 callerShardId;
    uint8 codeShardId;
}
```

However, there's an issue in the `getZkSyncMeta` function. This function is designed to retrieve the `ZkSyncMeta` structure, but it currently only fetches a subset of the fields. It correctly retrieves `gasPerPubdataByte`, `shardId`, `callerShardId`, and `codeShardId` from the provided `metaPacked` variable. Still, it neglects to retrieve `heapSize` and `auxHeapSize`.

```
    function getZkSyncMeta() internal view returns (ZkSyncMeta memory meta) {
        uint256 metaPacked = getZkSyncMetaBytes();
        meta.gasPerPubdataByte = getGasPerPubdataByteFromMeta(metaPacked);
        meta.shardId = getShardIdFromMeta(metaPacked);
        meta.callerShardId = getCallerShardIdFromMeta(metaPacked);
        meta.codeShardId = getCodeShardIdFromMeta(metaPacked);
    }
```

This omission is a problem because `heapSize` and `auxHeapSize` are important parameters that can affect how the system functions. They define the sizes of specific memory areas used by the system, and without them, some operations may not work correctly or efficiently. These fields should be included in the `ZkSyncMeta` structure to ensure that all necessary information is available for the proper operation of the system.

To address this issue, the recommended mitigation step is to add the missing lines of code within the `getZkSyncMeta` function to extract and assign the values of `heapSize` and `auxHeapSize` from `metaPacked`. This will ensure that the `ZkSyncMeta` struct contains all the required data and functions as intended.

## Tools Used
Manual / VsCode

## Recommended Mitigation Steps
To fix this issue, the missing fields heapSize and auxHeapSizecan be added to the getZkSyncMeta function by extracting them from the metaPacked variable and assigning them to the meta struct. This addition ensures that all necessary information is retrieved and made available in the ZkSyncMeta structure.
```
   meta.heapSize = getHeapSizeFromMeta(metaPacked);
   meta.auxHeapSize = getAuxHeapSizeFromMeta(metaPacked);
```
They can be added to the last lines of the getZkSyncMeta