xanoutas/solidity-security-findings huggingface dataset:
Axelar wouldn't be able to process executions from non-evm chains
Audit: 2024-08-axelar-network-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-axelar-network/blob/69c4f2c3fcefb1b8eb2129af9c3685a44ae5b6fe/interchain-token-service/contracts/InterchainTokenService.sol#L720-L776


# Vulnerability details


## Proof of Concept

Per conversations and informations provided by the sponsors during the audit, this update is supposed to work smoothly with both evm & non-evm chains, however this invariant doesn't hold, this is because whenever there is a need for transfers, the call route is: `InterchainTokenService#executeWith()/executeWithToken() -> InterchainTokenService#_processInterchainTransferPayload() -> _processInterchainTransferPayload#_giveToken() -> TokenHandler#giveToken() -> TokenManager#addFlowIn() -> TokenManager#_addFlow()`.

Now when processing the interchain transfer payload, there is a need to get the destination address https://github.com/code-423n4/2024-08-axelar-network/blob/69c4f2c3fcefb1b8eb2129af9c3685a44ae5b6fe/interchain-token-service/contracts/InterchainTokenService.sol#L720-L776

```solidity

    function _processInterchainTransferPayload(
        bytes32 commandId,
        address expressExecutor,
        string memory sourceChain,
        bytes memory payload
    ) internal {
        bytes32 tokenId;
        bytes memory sourceAddress;
        address destinationAddress;
        uint256 amount;
        bytes memory data;
        {
            bytes memory destinationAddressBytes;
            (, tokenId, sourceAddress, destinationAddressBytes, amount, data) = abi.decode(
                payload,
                (uint256, bytes32, bytes, bytes, uint256, bytes)
            );
            destinationAddress = destinationAddressBytes.toAddress();
        }

..snip
```

Evidently, this is done with the helper function from the [inherited](https://github.com/code-423n4/2024-08-axelar-network/blob/69c4f2c3fcefb1b8eb2129af9c3685a44ae5b6fe/interchain-token-service/contracts/InterchainTokenService.sol#L44-L45) `AddressBytes.sol`: https://github.com/code-423n4/2024-08-axelar-network/blob/69c4f2c3fcefb1b8eb2129af9c3685a44ae5b6fe/axelar-gmp-sdk-solidity/contracts/libs/AddressBytes.sol#L17-L23

```solidity
    function toAddress(bytes memory bytesAddress) internal pure returns (address addr) {
        if (bytesAddress.length != 20) revert InvalidBytesLength(bytesAddress);

        assembly {
            addr := mload(add(bytesAddress, 20))
        }
    }
```

Evidently, there is an enforcal that the addresses length must be `20`, now whereas this holds true for EVM chains, this isn't true for non-EVM chains as the length of the addresses `!=20`, which then causes the execution attempt to always revert [here](https://github.com/code-423n4/2024-08-axelar-network/blob/69c4f2c3fcefb1b8eb2129af9c3685a44ae5b6fe/interchain-token-service/contracts/InterchainTokenService.sol#L737-L738).

## Impact

As hinted under _Proof of concept_, executions are broken for non-evm chains since they'd always revert [here](https://github.com/code-423n
Cross chain calls can be permanently DOS'd due to collision of message Ids
Audit: 2024-08-axelar-network-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-axelar-network/blob/69c4f2c3fcefb1b8eb2129af9c3685a44ae5b6fe/axelar-amplifier/contracts/axelarnet-gateway/src/contract/execute.rs#L17-L60


# Vulnerability details


### Proof of Concept

Take a look at https://github.com/code-423n4/2024-08-axelar-network/blob/69c4f2c3fcefb1b8eb2129af9c3685a44ae5b6fe/axelar-amplifier/contracts/axelarnet-gateway/src/contract/execute.rs#L17-L60

```rust
pub(crate) fn call_contract(
    store: &mut dyn Storage,
    router: &Router,
    chain_name: ChainName,
    sender: Addr,
    destination_chain: ChainName,
    destination_address: Address,
    payload: HexBinary,
) -> Result<Response, Error> {
    let counter = state::increment_msg_counter(store).change_context(Error::InvalidStoreAccess)?;

    let message_id = HexTxHashAndEventIndex {
        tx_hash: PLACEHOLDER_TX_HASH,
        event_index: counter,
    }
    .to_string();

    let cc_id = CrossChainId {
        source_chain: chain_name.into(),
        message_id: nonempty::String::try_from(message_id)
            .change_context(Error::InvalidMessageId)?,
    };

    let payload_hash = Keccak256::digest(payload.as_slice()).into();

    let msg = Message {
        cc_id: cc_id.clone(),
        source_address: Address::try_from(sender.clone().into_string())
            .expect("failed to convert sender address"),
        destination_chain,
        destination_address,
        payload_hash,
    };

    state::save_incoming_msg(store, cc_id, &msg).change_context(Error::InvalidStoreAccess)?;

    let (wasm_msg, events) = route(router, vec![msg.clone()])?;

    Ok(Response::new()
        .add_message(wasm_msg)
        .add_event(AxelarnetGatewayEvent::ContractCalled { msg, payload }.into())
        .add_events(events))
}

```

This function is used in order to initiate a cross chain contract call, now to do this it [increases the message counter](https://github.com/code-423n4/2024-08-axelar-network/blob/69c4f2c3fcefb1b8eb2129af9c3685a44ae5b6fe/axelar-amplifier/contracts/axelarnet-gateway/src/contract/execute.rs#L26) to be used later on [for unique identification](https://github.com/code-423n4/2024-08-axelar-network/blob/69c4f2c3fcefb1b8eb2129af9c3685a44ae5b6fe/axelar-amplifier/contracts/axelarnet-gateway/src/contract/execute.rs#L28-L32).

Since when the message is received and needs to be saved [it is saved to the contract's state along with its cc_id, which includes the msg.id.](https://github.com/code-423n4/2024-08-axelar-network/blob/69c4f2c3fcefb1b8eb2129af9c3685a44ae5b6fe/axelar-amplifier/contracts/axelarnet-gateway/src/contract/execute.rs#L51) This action inherently requires the msg.id to be unique to prevent overwriting existing messages. And then we have to call `route_outgoing_messages()` to process these messages, where [there is a check against the cc_id and stored messages where if they diverge the execution reverts](https://github.com/code-423n4/2024-08-axelar-network/blob/69c4f2c3fcefb1b8eb2129af9
Source address does not correspond to the trusted source address in ITS Hub
Audit: 2024-08-axelar-network-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-08-axelar-network/blob/main/axelar-amplifier/interchain-token-service/src/contract/execute.rs#L31


# Vulnerability details

## Impact

In `execute.rs` contract of the ITS Hub, there is a function `execute_messages()` that gets the data and transmits it to the Axelarnet gateway. The problem is that when checking `source_address` it makes a mistake by comparing it with `trusted_source_address` as `source_address` is specified when triggering the message on ITS contract as `msg.sender` and not ITS contract itself.

## Proof of Concept

Take a look at `execute_messages()` functionality:

https://github.com/code-423n4/2024-08-axelar-network/blob/main/axelar-amplifier/interchain-token-service/src/contract/execute.rs#L27-33
```
  let source_chain = ChainName::try_from(cc_id.source_chain.clone().to_string())
        .change_context(Error::InvalidPayload)?;
    let trusted_source_address = load_trusted_address(deps.storage, &source_chain)
        .change_context(Error::InvalidStoreAccess)?;
    if source_address != trusted_source_address {
        return Err(report!(Error::UntrustedAddress(source_address)));
    }

```

We get `source_chain` from `cc_id` and then load trusted address for it meaning that the contract checks if the ITS contract that triggered the message is the trusted ITS contract on the source chain. But the problem is that `source_address` is set as `msg.sender` so it's the user who triggered `interchainTransfer()` transaction inside of ITS contract:

https://github.com/code-423n4/2024-08-axelar-network/blob/main/interchain-token-service/contracts/InterchainTokenService.sol#L467-469
```
 _transmitInterchainTransfer(
            tokenId,
            msg.sender,

```

https://github.com/code-423n4/2024-08-axelar-network/blob/main/interchain-token-service/contracts/InterchainTokenService.sol#L1148-1150

```
 function _transmitInterchainTransfer(
        bytes32 tokenId,
        address sourceAddress,

```

So it checks for incorrect address which will make the tx revert.

## Tools Used

Manual review.

## Recommended Mitigation Steps

Change the source address to ITS contract when specifying it inside of ITS contract.


## Assessed type

Other
Missing range constraint on remainder check in div opcode implementation
Audit: 2023-10-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-zksync/blob/main/code/era-zkevm_circuits/src/main_vm/opcodes/mul_div.rs#L312-L331


# Vulnerability details

When calculating the remainder of the `div` instruction, the circuit needs to verify that the remainder is less than the divisor. It does this by subtracting the divisor from the remainder and enforcing that the borrow flow is true.

https://github.com/code-423n4/2023-10-zksync/blob/main/code/era-zkevm_circuits/src/main_vm/opcodes/mul_div.rs#L314

```rust
// do remainder - divisor
let (subtraction_result_unchecked, remainder_is_less_than_divisor) =
    allocate_subtraction_result_unchecked(cs, &remainder_unchecked, src1_view);

// relation is a + b == c + of * 2^N,
// but we compute d - e + 2^N * borrow = f

// so we need to shuffle
let addition_relation = AddSubRelation {
    a: *src1_view,
    b: subtraction_result_unchecked,
    c: remainder_unchecked,
    of: remainder_is_less_than_divisor,
};

// unless divisor is 0 (that we handle separately),
// we require that remainder is < divisor
remainder_is_less_than_divisor.conditionally_enforce_true(cs, divisor_is_non_zero);
```

However, the code fails to range constrain the result of the subtraction. This allows `subtraction_result_unchecked` to contain limbs that are not representable by a 32-bit unsigned integer. We can use this to force `remainder_is_less_than_divisor` to be true even if the remainder is actually larger than the divisor.

## Impact
A malicious validator could generate and submit a proof with incorrect behavior of the `div` instruction. This would allow the validator to manipulate the behavior of smart contracts that use a `div` instruction. For example, the validator could manipulate the calculated price during the execution of an on-chain DEX and steal all of the assets in the DEX. Since every smart contract that uses a `div` instruction is affected, it is impossible to enumerate all potential impacts.

## Proof of Concept
For the ease of testing, we forked the zkSync Era test harness into a monorepo containing the VM and circuit code: https://github.com/chainlight-io/zksync-era-boojum-test-harness. The patch below can be applied to the test code to demonstrate the vulnerability:

```diff
diff --git a/run.sh b/run.sh
index 91e97da..97e2d3b 100644
--- a/run.sh
+++ b/run.sh
@@ -1,2 +1,3 @@
 #!/bin/sh
-cd zkevm_test_harness && RUST_MIN_STACK=$((8*1024*1024)) cargo test --jobs 1 -- --nocapture run_simple
+# XXX must run as release to avoid debug asserts
+cd zkevm_test_harness && RUST_MIN_STACK=$((8*1024*1024)) cargo test --jobs 1 --release -- --nocapture run_simple && RUST_MIN_STACK=$((8*1024*1024)) cargo test --jobs 1 --release -- --nocapture run_hack
diff --git a/zk_evm/src/opcodes/execution/div.rs b/zk_evm/src/opcodes/execution/div.rs
index f09d9b9..4e786d3 100644
--- a/zk_evm/src/opcodes/execution/div.rs
+++ b/zk_evm/src/opcodes/execution/div.rs
@@ -48,7 +48,11
Mailbox deposit function can unintentionally be bricked by a user
Audit: 2023-10-zksync-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
The mailbox.sol enforces a cap on the deposit limit, but withdrawing does not lower the limit.
The mailbox stops functioning when the limit is hit.

## Proof of Concept
https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/contracts/zksync/facets/Mailbox.sol#L279

When a user deposits to the system his deposit amount is increased, and required to be less than the limit. When a user withdraws the deposit amount is not decreased, meaning the user will eventually be locked out of depositing funds to the system.

This breaks the functionality of the bridge for that user.

## Recommended Mitigation Steps
Decrease the deposit limit of a user after a withdraw occurs. 


## Assessed type

Other
ZKSYNC_NEAR_CALL_executeL1Tx forward and mint too much ETH in bootloader.yul
Audit: 2023-10-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/system-contracts/bootloader/bootloader.yul#L1632
https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/contracts/zksync/facets/Mailbox.sol#L306


# Vulnerability details

## Impact

ZKSYNC_NEAR_CALL_executeL1Tx forward and mint too much ETH

## Proof of Concept

when process the transaction to zksync era network in bootloader

we are calling this [line of code](https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/system-contracts/bootloader/bootloader.yul#L1632)

the code tries to [mint ETH first](https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/system-contracts/bootloader/bootloader.yul#L1656C10-L1662C1) and then forward the ETH when executing the transaction

```solidity
let value := getValue(innerTxDataOffset)
if value {
	mintEther(from, value, true)
}

success := executeL1Tx(innerTxDataOffset, from)
```

as we can see, first ETH is minted

and then executeL1Tx [forward ETH](https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/system-contracts/bootloader/bootloader.yul#L2331) as well

```solidity
let value := getValue(innerTxDataOffset)
debugLog("value", value)
let dataPtr := getDataPtr(innerTxDataOffset)

let dataLength := mload(dataPtr)
let data := add(dataPtr, 32)

ret := msgValueSimulatorMimicCall(
	to,
	from,
	value,
	dataPtr
)
```

the problem is that on l1 side, the code does not [validate](https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/contracts/zksync/facets/Mailbox.sol#L306) the mitned ETH amount and forward ETH amount

```solidity
{
params.l2GasPrice = _isFree ? 0 : _deriveL2GasPrice(tx.gasprice, _l2GasPerPubdataByteLimit);
uint256 baseCost = params.l2GasPrice * _l2GasLimit;
require(msg.value >= baseCost + _l2Value, "mv"); // The `msg.value` doesn't cover the transaction cost
}
```

for example, 

if we set _l2Value to 3 ETH and provide 5 ETH as msg.value,

in l2 when boatloader processing transaction, 3 ETH minted, 3 ETH is forwarded, cause inflation spending.

## Tools Used

Manual Review

## Recommended Mitigation Steps

validate the minted ETH and amount and forward ETH amount properly


## Assessed type

Invalid Validation
Improper usage of `unsafe` in the conditional allocation function allows for injection of crafted inputs near the max value of `UInt32`
Audit: 2023-10-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/storage_application/mod.rs#L42
https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/main_vm/pre_state.rs#L145
https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/main_vm/pre_state.rs#L147
https://github.com/matter-labs/era-zkevm_circuits/blob/main/src/main_vm/pre_state.rs#L149


# Vulnerability details

## Summary

The ZkSync Era codebase contains instances of the `unsafe` keyword, which is used to bypass Rust's memory safety checks. Specifically, in the `storage_application/mod.rs` file, the `conditionally_allocate_with_default_biased` and related functions employ `unsafe` operations to manipulate data. If not used correctly, these operations can lead to undefined behavior and possible vulnerabilities.

## Vulnerability Detail

Rust's `unsafe` keyword allows developers to bypass the language's memory safety guarantees. However, this power comes at a cost. Misuse of `unsafe` can lead to memory errors, such as buffer overflows and data races, which can be exploited by attackers.

In the provided code snippet from `storage_application/mod.rs`, the `unsafe` keyword is used in several places, especially when dealing with memory operations:

```rust
let carry_as_u32 = unsafe { UInt32::from_variable_unchecked(carry.get_variable()) };
```

This operation can be risky, as the unchecked conversion may not always be valid. If the underlying data does not conform to the expectations of the `UInt32::from_variable_unchecked` function, this can lead to undefined behavior.

Furthermore, In the `pre_state` function, there are multiple instances of `unsafe` being used to call the `increment_unchecked` method on `UInt32`:

```rust
let timestamp_for_first_decommit_or_precompile_read =
    unsafe { timestamp_for_code_or_src_read.increment_unchecked(cs) };
let timestamp_for_second_decommit_or_precompile_write =
    unsafe { timestamp_for_first_decommit_or_precompile_read.increment_unchecked(cs) };
let timestamp_for_dst_write =
    unsafe { timestamp_for_second_decommit_or_precompile_write.increment_unchecked(cs) };
let next_cycle_timestamp = unsafe { timestamp_for_dst_write.increment_unchecked(cs) };
```

This method appears to increment a `UInt32` without performing a bounds check. If the value overflows, it may wrap around, leading to unexpected behavior. 

The `unsafe` keyword is also used in the `memory_location_for_src0` calculation:

```rust
let stack_page = unsafe { base_page.increment_unchecked(cs) };
let heap_page = unsafe { stack_page.increment_unchecked(cs) };
let aux_heap_page = unsafe { heap_page.increment_unchecked(cs) };
```

Given that these unchecked increments are directly related to memory access operations (timestamps and page calculation), an attacker may be able to exploit the system by manipulating the inputs in a way that causes these increments to overflow.

## Impact

The insecure usage of `unsafe` may lead to:

1. Undefined behavior in th
Lack of Test
Audit: 2023-10-zksync-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
There are very few tests for most functionalities.

***For example, Mailbox.sol (particularly MailboxFacet) is a key contract for the L1 bridge, and has 360+ lines of code and a large dependency tree of aggregated thousands of lines of non-library solidity code (specific to this codebase). The code implements sensitive functionality with many important details and execution branches. However, there are only four basic tests in Mailbox.t.sol. This means that the entirety of the MailboxFacet functionality is untested in this repository.***

## POC
***This leads to several potential issues:***
***The correctness of the code can only be assessed based on partial, and changing documentation. This is because intended and unintended behavior is not captured in tests.
Introduction of new vulnerabilities for established code in future code changes, since known positive and negative behaviors are not checked automatically.
Higher likelihood of missed vulnerabilities in current and future development and review.***

## Recommended Mitigation Steps
Consider adding contract-level testing to test all branches of execution. Additionally, consider implementing an ongoing measurement of testing coverage as a way to ensure at least 95% coverage


## Assessed type

Other
SystemContext.sol#L183 : Incorrect indexing leads to placing the latest BlockHash as older .
Audit: 2023-10-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/system-contracts/contracts/SystemContext.sol#L183


# Vulnerability details

## Impact

We observed the following issues with this.

1. The latest Blockhask would be stored at start location (older one)
2. When for happen from this BlockHash, incorrect BlockHash would be used as latest.

## Proof of Concept

On L2, there is SystemContext contract which gives about the L2 block information such as time, number and block hash, virtual block information . This virtual block would be used when transition from Batch to L2 Block number.

The total number of hashes to recorder are,

```solidity
    /// @notice The number of latest L2 blocks to store.
    /// @dev EVM requires us to be able to query the hashes of previous 256 blocks.
    /// We could either:
    /// - Store the latest 256 hashes (and strictly rely that we do not accidentally override the hash of the block 256 blocks ago)
    /// - Store the latest 257 blocks's hashes.
    uint256 internal constant MINIBLOCK_HASHES_TO_STORE = 257;
```

whenever the L2 block is built, the bootloader calls the [setL2Block](https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/system-contracts/contracts/SystemContext.sol#L312) function with l2 block number, timestamp and other parameters which are necessary to decide the block parameters.

The function flow calls the [_setL2BlockHash](https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/system-contracts/contracts/SystemContext.sol#L183) where the blockHash is stored in an array based on modulo division based index.

https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/system-contracts/contracts/SystemContext.sol#L183-L185

```solidity
    function _setL2BlockHash(uint256 _block, bytes32 _hash) internal {
        l2BlockHash[_block % MINIBLOCK_HASHES_TO_STORE] = _hash;
    }
```

the issue here is, whenever, the _block number comes as multiple of MINIBLOCK_HASHES_TO_STORE, the modular division would return the 0 value.

Lets say, l2BlockHash[] stored hash value at 0th index, when the block number reaches to MINIBLOCK_HASHES_TO_STORE, again the hash for block MINIBLOCK_HASHES_TO_STORE will be stored in the 0th index again.

## Tools Used

Manual review.

## Recommended Mitigation Steps

Update the below function.

So that when there is already Hash is there at 0th index, don't udate. Instead, store the hash at the given block number's index.

https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/system-contracts/contracts/SystemContext.sol#L183-L185

    function _setL2BlockHash(uint256 _block, bytes32 _hash) internal {
        l2BlockHash[_block % MINIBLOCK_HASHES_TO_STORE] = _hash;
    }


## Assessed type

Math