xanoutas/solidity-security-findings huggingface dataset:
OracleHelper.getEthPriceInUSD does not consider arbitrum sequencer uptime  when validating chainlink answer.
Audit: 2024-02-wise-lending-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseOracleHub/OracleHelper.sol#L270


# Vulnerability details

## Details
According to the project description, wiselending would be launched on both eth mainnet and arbitrum chains. The chainlink pricefeed in `OracleHelper` validates the chainlink price to ensure it does not return stale price through the `_chainlinkIsDead` function. Additionally, it also does the check for sequencer uptime if on arbitrum chain through a separate function `sequencerIsDead`.  It then combines both checks in the `WiseOracleHub.chainlinkIsDead` function. The `_chainlinkIsDead` validation is used within `OracleHelper.getETHPriceInUSD` which returns the price of ETH in USD. 
```
src: contracts/WiseOracleHub/OracleHelper.sol
 function getETHPriceInUSD()
        public
        view
        returns (uint256)
    {
@>       if (_chainLinkIsDead(ETH_USD_PLACEHOLDER) == true) {
            revert OracleIsDead();
        }

        return _validateAnswer(
            ETH_USD_PLACEHOLDER
        );
    }
```
This function is then used in `WiseOracleHub.getTokensPriceInUSD` and `WiseOracleHub.getTokensPriceFromUSD`. The issue comes in because using just the `_chainlinkIsDead` function to get eth price in OracleHelper does not consider whether the current chain is arbitrum.

## Impact
A user on arbitrum who calls the `OracleHelper.getEthPrice` and the other functions which rely on this including `WiseOracleHub.getTokensPriceInUSD` and `WiseOracleHub.getTokensPriceFromUSD` either directly or through usage of the protocol may falsely assume that the price it returns is validated on the arbitrum chain although the arbitrum sequencer may be  dead. This can also impact other aspects of the protocol as well as any other external protocols which may rely on the data from these functions as these are potentially very important functions.

## Proof of Concept
If the user who calls these functions is on arbitrum, they would get an answer which have not passed through the sequencer validation on the arbitrum chain. There may be an assumption that only users on eth mainnet would call these functions, however, this is not explicitly stated or dissallowed.

## Tools Used
Manual review
## Recommended Mitigation Steps
1. Use both the `chainlinkIsDead` and `sequencerIsDead` functions in the OracleHelper.getETHPriceInUSD`.

```diff
 function getETHPriceInUSD()
        public
        view
        returns (uint256)
    {

+     if (sequencerIsDead == true) {
+            revert OracleIsDead();
        }
      if (_chainLinkIsDead(ETH_USD_PLACEHOLDER) == true) {
           revert OracleIsDead();
       }

        return _validateAnswer(
            ETH_USD_PLACEHOLDER
        );
    }

```
2. Additionally, if these functions are expected to be called only by eth mainnet users, then it should be explicitly dissallowed if the user is not on eth mainnet.

```diff

 function getE
Security breaches in Aave or Pendle Power Farms may lead to Wise Lending asset loss.
Audit: 2024-02-wise-lending-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WrapperHub/AaveHub.sol#L122-L151
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/PowerFarms/PendlePowerFarmController/PendlePowerFarmController.sol#L113-L170


# Vulnerability details

## Impact
If an integrated system, such as Aave or Pendle Power Farms, experiences a security breach or exploit, it could lead to the loss of funds stored in the Wise Lending protocol. Attackers may be able to drain liquidity, steal assets, or manipulate the external system's functionality to their advantage.

> Cascading failures in an integrated system can propagate to the Wise Lending protocol, causing cascading failures or unexpected behavior. **For example, if Aave experiences a liquidity crisis or a critical bug, it could disrupt the borrowing and lending functionality in the Wise Lending protocol.**

## Proof of Concept
Integration with external systems such as the Aave protocol and Pendle Power Farms, introduces additional security risks and considerations.

`AaveHub` contract interacts with the Aave protocol for lending and borrowing functionality. The `depositExactAmount` function: [AaveHub.sol#depositExactAmount](https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WrapperHub/AaveHub.sol#L122-L151)

```solidity
function depositExactAmount(
    uint256 _nftId,
    address _underlyingAsset,
    uint256 _amount
)
    public
    nonReentrant
    validToken(_underlyingAsset)
    returns (uint256)
{
    _safeTransferFrom(
        _underlyingAsset,
        msg.sender,
        address(this),
        _amount
    );

    uint256 lendingShares = _wrapDepositExactAmount(
        _nftId,
        _underlyingAsset,
        _amount
    );

    emit IsDepositAave(
        _nftId,
        block.timestamp
    );

    return lendingShares;
}
```

The `depositExactAmount` function transfers the underlying asset from the user to the `AaveHub` contract and then calls the internal [`_wrapDepositExactAmount`](https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WrapperHub/AaveHub.sol#L139-L143) function to interact with Aave for depositing the funds.

The `PendlePowerFarmController` contract integrates with Pendle Power Farms for yield farming functionality. The `exchangeLpFeesForPendleWithIncentive` function: [PendlePowerFarmController.sol#exchangeLpFeesForPendleWithIncentive](https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/PowerFarms/PendlePowerFarmController/PendlePowerFarmController.sol#L113-L170)

```solidity
function exchangeLpFeesForPendleWithIncentive(
    address _pendleMarket,
    uint256 _pendleChildShares
)
    external
    syncSupply(_pendleMarket)
    returns (
        uint256,
        uint256
    )
{
    // ...

    uint
No check for checking the "to" address to not be zero address in _execute() function of DefaultAccount.sol
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
The "to" address can be zero address while converting from uint256 to uint160.

## Proof of Concept
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.0;

contract Test {

    uint256 public to = 2**160;

    function check() external view {

        assert(address(uint160(to)) == address(0));
    }
}

## Tools Used
Remix ide

## Recommended Mitigation Steps
Recommended to add (to != address(0));
Underflow if enough amount is sent to the contract
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact

In function withdraw 

     function withdraw(address _l1Receiver) external payable override {
        uint256 amount = msg.value;

        // Silent burning of the ether
        unchecked {
  
            balance[address(this)] -= amount;
            totalSupply -= amount;
        }

they are using unchecked to decrease balances. The issue here is that they are not checking that balance[address(this)] -= amount > 0, so if the msg.sender is sending more ether than what it is holded in the contract, the balance will underflow for the mapping:  balance[address(this)] -= amount;



## Proof of Concept
Case: balance[address(this)] -= amount = 100
we are sending 500

     interface Underflow{
     function withdraw(address _l1Receiver) external payable override ;
    }


     contract AttackUnder{

    function Pay()external{
        Underflow(0xdD870fA1b7C4700F2BD7f44238821C26f7392148).withdraw{value:500}(address(this));
     }
    }

    After: balance[address(this)] -= amount = 2 **256 - 400;


## Tools Used
Manual

## Recommended Mitigation Steps
Check that balance[address(this)] -= amount > 0 before burning
The "totalRequiredBalance()" function in the TransactionHelper.sol library can compute address(uint160(_transaction.paymaster) as zero address even when _transaction.paymaster is non-zero
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-zksync//blob/main/contracts/libraries/TransactionHelper.sol#L405


# Vulnerability details

## Impact
A user may provide a non-zero entry for the "_transaction.paymaster" field for a transaction to ensure they do not have to pay the gas fees. However, certain values of "_transaction.paymaster" >= 2^160 can result in address(uint160(_transaction.paymaster) to be equal to zero address, thus, requiring the user to pay the gas as well as the value.

## Proof of Concept
The below solidity contract illustrates the bug. The "Test" contract has a state variable "transactionPaymaster" that corresponds to "_transaction.paymaster" in the transaction struct. This state variable has a specific value (2^160). 

We can clearly see that the function "check()" in the "Test" contract does not revert, that is, the assert test passes. This shows that the computation address(uint160(transactionPaymaster) results in zero address even when transactionPaymaster is non-zero. This computation is the same as found in the mentioned vulnerable line of the TransactionHelper.sol library. 

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.0;

contract Test {

    uint256 public transactionPaymaster = 2**160;

    function check() external view {

        assert(address(uint160(transactionPaymaster)) == address(0));
    }
}

## Tools Used
Remix IDE

## Recommended Mitigation Steps
It is recommended to use uint160 instead of uint256 for the paymaster field of a transaction struct. 
OR
It is recommended to check for (_transaction.paymaster != 0) before checking for (address(uint160(_transaction.paymaster)) != address(0)).
Unchecked return value of call will allow to send messages marked as sent but will fail due to not enough gas
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
On the  sendTol1 function, they are sending the message via the SystemContractHelper:

   SystemContractHelper.toL1(true, bytes32(uint256(uint160(msg.sender))), hash);

 the problem relies on the fact that they are not checking whether the message was actually sent.

        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)
        }

 let success := call(_isService, callAddr, _key, _value, 0xFFFF, 0, 0)

There is no handling return of call. Anyone can send a message with less than 0xFFFF gas and the message will directly fail to deliver marking it as sent:

         emit L1MessageSent(msg.sender, hash, _message);

## Proof of Concept
    interface NoGas{
    function sendToL1(bytes calldata _message) external ;
     }


    contract BrickMessage{

    function noMessage()external{
        NoGas(0xdD870fA1b7C4700F2BD7f44238821C26f7392148).sendToL1{gas:50000}("0x0");
    }


      }


## Tools Used
Manual

## Recommended Mitigation Steps
Require that the call was successful

(bool suc,) = SystemContractHelper.toL1(true, bytes32(uint256(uint160(msg.sender))), hash);

require(succ, "wrong");
Unchecked msg.value will lead to losing funs inside the contract
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact

While paying for the transaction, 


    function payForTransaction(
        bytes32, // _txHash
        bytes32, // _suggestedSignedHash
        Transaction calldata _transaction
    ) external payable ignoreNonBootloader ignoreInDelegateCall {
        //@audit-issue no checks that actulayy there is msg.value. If that value is not sent, if there 
      are funds in the vootloader, it will be paid from there, causing free transactions

        /**
        
    function payToTheBootloader(Transaction calldata _transaction) internal returns (bool success) {
        address bootloaderAddr = BOOTLOADER_FORMAL_ADDRESS;
        uint256 amount = _transaction.maxFeePerGas * _transaction.gasLimit;

        assembly {
            success := call(gas(), bootloaderAddr, amount, 0, 0, 0, 0)
        }
    }
        */
        bool success = _transaction.payToTheBootloader();
        require(success, "Failed to pay the fee to the operator");
    }


You can see that on the external call to `bootloaderAddr` they are sending an amount to pay for the gas, which is intended to come from the payForTransaction function because it is payable. The issue is that they do not check whether the amount was actually sent. Therefore funds already in the contract, will be sent as the amount to the `bootloaderAddr`

## Proof of Concept

Test to confirm that. Add the specific params that you want as the transaction:


     interface PayT{
     function payForTransaction(
        bytes32, // _txHash
        bytes32, // _suggestedSignedHash
        Transaction calldata _transaction
    ) external;

        struct Transaction {
    // The type of the transaction.
    uint256 txType;
    // The caller.
    uint256 from;
    // The callee.
    uint256 to;
    // The gasLimit to pass with the transaction.
    // It has the same meaning as Ethereum's gasLimit.
    uint256 gasLimit;
    // The maximum amount of gas the user is willing to pay for a byte of pubdata.
    uint256 gasPerPubdataByteLimit;
    // The maximum fee per gas that the user is willing to pay.
    // It is akin to EIP1559's maxFeePerGas.
    uint256 maxFeePerGas;
    // The maximum priority fee per gas that the user is willing to pay.
    // It is akin to EIP1559's maxPriorityFeePerGas.
    uint256 maxPriorityFeePerGas;
    // The transaction's paymaster. If there is no paymaster, it is equal to 0.
    uint256 paymaster;
    // The nonce of the transaction.
    uint256 nonce;
    // The value to pass with the transaction.
    uint256 value;
    // In the future, we might want to add some
    // new fields to the struct. The `txData` struct
    // is to be passed to account and any changes to its structure
    // would mean a breaking change to these accounts. In order to prevent this,
    // we should keep some fields as "reserved".
    // I
EVM Elliptic Curve Recovery Discrepancy
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-zksync/blob/main/contracts/precompiles/Ecrecover.yul#L62


# Vulnerability details

## Impact

The `Ecrecover.yul` file meant to simulate the `ecrecover` mechanism as executed by traditional ETH 1.0 consensus mechanisms is incorrect. In detail, it does not conform to the "Homestead" update which introduced an upper-bound check for `s` values of an `(r, s, v)` ECDSA payload to **prohibit malleable signatures**.

All major ETH 1.0 clients (i.e. `go-ethereum`, `nethermind`) prevent `s` values as input in `ecrecover` instructions if the value lies in the upper half of the `secp256k1` curve order. To illustrate:

- `go-ethereum`: https://github.com/ethereum/go-ethereum/blob/b628d72/crypto/crypto.go#L266-L270
- `nethermind`: https://github.com/NethermindEth/nethermind/blob/fd34651/src/Nethermind/Nethermind.Crypto/EthereumEcdsa.cs#L22-L24

The consensus discrepancy at hand illustrates a security feature present in ETH 1.0 clients and absent in the `zkEVM`. As such, a contract that would be secure when deployed in ETH 1.0 will not be so when deployed in the zkEVM. This vulnerability allows malleable signatures to be consumed thus opening up potential replay-attack vectors that would otherwise be impossible in ETH 1.0.

The `ecrecover` function lies at the heart of multiple authorization systems in use by smart contracts, meaning that a significant amount of funds would be affected by this discrepancy.

## Proof of Concept

An `ecrecover` call with an `s` value that is greater than or equal to `0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A1` should fail execution, however, the operation properly succeeds in the zkEVM. A minimalistic contract that illustrates the issue:

```sol
contract ECRecoverVulnerability {
    function test(uint8 v, uint256 r, uint256 s) external view {
        require(s >= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A1, "S value be in upper-half of secp256k1 curve order");
        ecrecover(r, s, v);
        revert("ISSUE: Should not have reached here");
    }
}
```

## Tools Used

Manual review, ETH 1.0 clients, Ethereum Foundation release guidelines.

## Recommended Mitigation Steps

We advise the upper bound evaluation to be performed similarly to the `SECP256K1_GROUP_SIZE` bound check already applied to the codebase, utilizing the `nethermind` coding style [which divides the group size by `2`](https://github.com/ethereum/go-ethereum/blob/b628d72/crypto/crypto.go#L49).
Contracts are susceptible for Head Overflow Bug in Calldata
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/libraries/TransactionHelper.sol#L117-L142
https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/DefaultAccount.sol#L77-L87
https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/L2EthToken.sol#L97-L99


# Vulnerability details

## Impact
ABI-encoding a tuple with a statically-sized calldata array in the last component would corrupt 32 leading bytes of its first dynamically encoded component.

## Proof of Concept

The functions are taking input arguments as calldata.

Following contracts are using the family of abi.encoding with the data provided input as calldata.
`TransactionHelper.sol,
DefaultAccount.sol,
L2EthToken.sol`

when we look at the function in `TransactionHelper.sol` - `_encodeHashEIP712Transaction`, it takes the stucure of call data as input and does abi.encoding. 

As per the solidity page update in the list of known bugs,`https://blog.soliditylang.org/2022/08/08/calldata-tuple-reencoding-head-overflow-bug/`

The list of criteria where this issue would be possible are,

 1.The last component of the tuple is a (potentially nested) statically-sized calldata array with the most base type being either uint or bytes32. E.g. bytes32[10] or uint[2][2][2]
 2.The tuple contains at least one dynamic component. E.g. bytes or a struct containing a dynamic array.
 3.The code is using ABI coder v2, which is the default since Solidity 0.8.0.

when we look at the `Transaction` ,

  struct Transaction {
    // The type of the transaction.
    uint256 txType;
    // The caller.
    uint256 from;
    // The callee.
    uint256 to;
    // The gasLimit to pass with the transaction.
    // It has the same meaning as Ethereum's gasLimit.
    uint256 gasLimit;
    // The maximum amount of gas the user is willing to pay for a byte of pubdata.
    uint256 gasPerPubdataByteLimit;
    // The maximum fee per gas that the user is willing to pay.
    // It is akin to EIP1559's maxFeePerGas.
    uint256 maxFeePerGas;
    // The maximum priority fee per gas that the user is willing to pay.
    // It is akin to EIP1559's maxPriorityFeePerGas.
    uint256 maxPriorityFeePerGas;
    // The transaction's paymaster. If there is no paymaster, it is equal to 0.
    uint256 paymaster;
    // The nonce of the transaction.
    uint256 nonce;
    // The value to pass with the transaction.
    uint256 value;
    // In the future, we might want to add some
    // new fields to the struct. The `txData` struct
    // is to be passed to account and any changes to its structure
    // would mean a breaking change to these accounts. In order to prevent this,
    // we should keep some fields as "reserved".
    // It is also recommended that their length is fixed, since
    // it would allow easier proof integration (in case we will need
    // some special circuit for preproce
Incorrect usage of EIP-150
Audit: 2023-03-zksync-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/ContractDeployer.sol#L323
https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/DefaultAccount.sol#L83
https://github.com/code-423n4/2023-03-zksync/blob/21d9a364a4a75adfa6f1e038232d8c0f39858a64/contracts/DefaultAccount.sol#L151


# Vulnerability details

## Impact
Detailed description of the impact of this finding.

## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

## Tools Used

## Recommended Mitigation Steps