xanoutas/solidity-security-findings huggingface dataset:
Anyone can burn tokens in `ZetaNonEth` using the `ERC20Burnable.burn` function
Audit: 2023-11-zetachain-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/main/repos/protocol-contracts/contracts/evm/Zeta.non-eth.sol#L73-L82


# Vulnerability details

## Impact

In `ZetaNonEth` contract the only address supposed to have the ability the burn tokens is the connector address through the `burnFrom` function, but any user can call the ERC20Burnable built-in `burn` function directly and burn his tokens without passing through the connector.

## Proof of Concept

The openzeppelin ERC20Burnable contract (check [here](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/ERC20Burnable.sol)) contains both the `burnFrom` and `burn` functions that can be overridden, in the `ZetaNonEth` contract only the `burnFrom` function is overridden to allow only the connector to burn tokens.

Thus any user can call the built-in `burn` function to burn his tokens without passing through the connector.

## Tools Used

Manual review

## Recommended Mitigation Steps

Override the openzeppelin ERC20Burnable `burn` function in `ZetaNonEth` contract :
```solidity
function burn(uint256 value) public override {
    revert();
}
```


## Assessed type

Access Control
The safeCreate2Internal check of code size
Audit: 2023-11-zetachain-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/main/repos/protocol-contracts/contracts/evm/tools/ImmutableCreate2Factory.sol#L26


# Vulnerability details

## Impact
Detailed description of the impact of this finding.
The safeCreate2Internal function does not check if the contract creation was successful by checking if the code size at the deployment address is greater than zero. Instead, it only checks if the returned address matches the expected address. If the contract creation fails (e.g., out of gas, revert in constructor), the contract will still be marked as deployed in the _deployed mapping, which could lead to inconsistencies.

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


function safeCreate2Internal(
        bytes32 salt,
        bytes memory initializationCode
    ) internal returns (address deploymentAddress) {
        // move the initialization code from calldata to memory.
        bytes memory initCode = initializationCode;

        // determine the target address for contract deployment.
        address targetDeploymentAddress = address(
            uint160( // downcast to match the address type.
                uint256( // convert to uint to truncate upper digits.
                    keccak256( // compute the CREATE2 hash using 4 inputs.
                        abi.encodePacked( // pack all inputs to the hash together.
                            hex"ff", // start with 0xff to distinguish from RLP.
                            address(this), // this contract will be the caller.
                            salt, // pass in the supplied salt value.
                            keccak256(abi.encodePacked(initCode)) // pass in the hash of initialization code.
                        )
                    )
                )
            )
        );

        // ensure that a contract hasn't been previously deployed to target address.
        require(!_deployed[targetDeploymentAddress], "Invalid contract creation - contract has already been deployed.");

        // using inline assembly: load data and length of data, then call CREATE2.
        assembly {
            // solhint-disable-line
            let encoded_data := add(0x20, initCode) // load initialization code.
            let encoded_size := mload(initCode) // load the init code's length.
            deploymentAddress := create2(
                // call CREATE2 with 4 arguments.
                callvalue, // forward any attached value.
                encoded_data, // pass in initialization code.
                encoded_size, // pass in init code's length.
                salt // pass in the salt value.
            )
        }

        // check address against target to ensure that deployment was successful.
        require(
            deploymentAddress == targetDeploymentAddress,
            "Failed to deploy contract using provided salt and in
AddToInTxTracker doens't allow permissionless tx validation for Bitcoin chain, InTxTracker permissionless tx validation for Bitcoin chain will always fail
Audit: 2023-11-zetachain-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/crosschain/keeper/msg_server_add_to_intx_tracker.go#L38-L39


# Vulnerability details

## Impact
Permissionless tx validation for EVM and Bitcoin chain should be supported based on contest [doc](https://github.com/code-423n4/2023-11-zetachain/blob/main/docs/important-areas.md)`→ The system is currently implemented for Ethereum/BSC and Bitcoin`. However, currently permissionless tx validation for EVM and Bitcoin chain are only supported in `AddToOutTxTracker`, but not supported in `AddToInTxTracker`. Permissionless validation for InTx for bitcoin chain will always fail. 

## Proof of Concept
In `AddToInTxTracker()` from msg_server_add_to_intx_tracker.go, chain is incorrectly diverted. The bitcoin chain is missing and will return an error.

```go
//x/crosschain/keeper/msg_server_add_to_intx_tracker.go
func (k msgServer) AddToInTxTracker(goCtx context.Context, msg *types.MsgAddToInTxTracker) (*types.MsgAddToInTxTrackerResponse, error) {
...
		if common.IsEVMChain(msg.ChainId) {
			err = k.VerifyEVMInTxBody(ctx, msg, txBytes)
			if err != nil {
				return nil, types.ErrTxBodyVerificationFail.Wrapf(err.Error())
			}
} else {
               //@audit when ChainId is bitCoin chain, this will return an error
|>			return nil, types.ErrTxBodyVerificationFail.Wrapf(fmt.Sprintf("cannot verify inTx body for chain %d", msg.ChainId))
		}
```
(https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/crosschain/keeper/msg_server_add_to_intx_tracker.go#L38-L39)

Notice in `AddToOutTxTracker()`, bitcoin chain is correctly diverted with ` else if common.IsBitcoinChain(msg.ChainId)`statement.

## Tools Used
Manual review

## Recommended Mitigation Steps
In `AddToInTxTracker()`, add `IsBitcoinChain(msg.ChainId)` to correctly handle when chainId is bitcoin chain.


## Assessed type

Error
`ZRC20.transferFrom` uses allowance even if `_msgSender() == sender`
Audit: 2023-11-zetachain-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/main/repos/protocol-contracts/contracts/zevm/ZRC20.sol#L157-L166


# Vulnerability details

## Impact

`ZRC20.transferFrom` attempts to use allowance even when spender = sender (from). This breaks compatibility with a large number of protocol who opt to use the transferFrom method all the time (pull only) instead of using both transfer and transferFrom (push and pull). The ERC20 standard only does an allowance check when spender != sender (from). The result of this difference will likely result in tokens becoming irreversibly stranded across different protocols.

## Proof of Concept

The `ZRC20.transferFrom` method shown below always uses allowance even if `_msgSender() = sender` :

```solidity
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
    _transfer(sender, recipient, amount);

    // @audit transferFrom uses allowance even if sender == _msgSender()
    uint256 currentAllowance = _allowances[sender][_msgSender()];
    if (currentAllowance < amount) revert LowAllowance();

    _approve(sender, _msgSender(), currentAllowance - amount);

    return true;
}
```

This will result in the token not being be compatible with some protocols and will end up stranded.

## Tools Used

Manual review

## Recommended Mitigation Steps

Only use allowance when `_msgSender() != sender` :

```solidity
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
    _transfer(sender, recipient, amount);

    // @audit use allowance when `_msgSender() != sender`
    if (_msgSender() != sender) {
        uint256 currentAllowance = _allowances[sender][_msgSender()];
        if (currentAllowance < amount) revert LowAllowance();

        _approve(sender, _msgSender(), currentAllowance - amount);
    }
    
    return true;
}
```


## Assessed type

ERC20
Contract Inheritance: no inherit from ZetaTokenConsumer
Audit: 2023-11-zetachain-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/main/repos/protocol-contracts/contracts/evm/tools/ZetaTokenConsumerUniV2.strategy.sol#L17


# Vulnerability details

## Impact
Detailed description of the impact of this finding.
Contract Inheritance: The contract is supposed to inherit from ZetaTokenConsumer, but the code for this base contract is not provided. It's important to review the base contract for any additional security considerations.

## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.
https://github.com/code-423n4/2023-11-zetachain/blob/main/repos/protocol-contracts/contracts/evm/tools/ZetaTokenConsumerUniV2.strategy.sol#L17


## Tools Used
Manual Analysis

## Recommended Mitigation Steps
 inherit 


## Assessed type

Context
MAX_DEADLINE
Audit: 2023-11-zetachain-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/main/repos/protocol-contracts/contracts/evm/tools/ZetaTokenConsumerUniV2.strategy.sol#L19


# Vulnerability details

## Impact
Detailed description of the impact of this finding.
MAX_DEADLINE: The contract uses a constant MAX_DEADLINE to set the deadline for the swap. This could be problematic if the blockchain is congested and transactions take longer to be mined. It's usually better to allow the user to specify the deadline.

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

 uint256[] memory amounts = uniswapV2Router.swapExactETHForTokens{value: msg.value}(
            minAmountOut,
            path,
            destinationAddress,
            block.timestamp + MAX_DEADLINE
        );

## Tools Used
Manual Analysis
## Recommended Mitigation Steps
It's usually better to allow the user to specify the deadline.



## Assessed type

Context
Approval Front-Running:
Audit: 2023-11-zetachain-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/main/repos/protocol-contracts/contracts/evm/tools/ZetaTokenConsumerUniV2.strategy.sol#L68


# Vulnerability details

## Impact
Detailed description of the impact of this finding.
Approval Front-Running: The contract approves the Uniswap router to spend tokens on behalf of the user. If the user calls the function again before the first transaction is mined, this could lead to a front-running attack where the second transaction could use the approval of the first transaction. To mitigate this, the contract could use the increaseAllowance and decreaseAllowance methods instead of approve.


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

        IERC20(inputToken).safeApprove(address(uniswapV2Router), inputTokenAmount);

## Tools Used
Manual Analysis
## Recommended Mitigation Steps
To mitigate this, the contract could use the increaseAllowance and decreaseAllowance methods instead of approve.



## Assessed type

Other
gasIncrease is vulnerable to single chain failure, gasIncrease fo all chains can be DOSsed if one chain doesn't have enough gas in stability pool
Audit: 2023-11-zetachain-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/crosschain/keeper/abci.go#L47-L49


# Vulnerability details

## Impact
current `IterateAndUpdateCctxGasPrice()` is vulnerable to be DOSsed, whenever a single chain doesn’t have enough gas tokens in gas stability pool. 

## Proof of Concept
The gas increase is implemented in x/crosschain/keeper/abci.go, `IterateAndUpdateCctxGasPrice()` where all chains are iterated in a for_loop. The vulnerability is that whenever one iteration of a chain returns an error, the whole function will be returned, the remaining chains that have been iterated in the for_loop will not be processed.

```go
//x/crosschain/keeper/abci.go
func (k Keeper) IterateAndUpdateCctxGasPrice(ctx sdk.Context) error {
...
	// iterate all chains' pending cctx
	chains := common.DefaultChainsList()
	for _, chain := range chains {
		res, err := k.CctxAllPending(sdk.UnwrapSDKContext(ctx), &types.QueryAllCctxPendingRequest{
			ChainId: chain.ChainId,
		})
		if err != nil {
			return err
		}

		// iterate through all pending cctx
		for _, pendingCctx := range res.CrossChainTx {
			if pendingCctx != nil {
                //@audit when there is not enough gas token for a given chain, `CheckAndUpdateCctxGasPrice()` will return an error, which will exit the function
|>				_, _, err := k.CheckAndUpdateCctxGasPrice(ctx, *pendingCctx, gasPriceIncreaseFlags)
				if err != nil {
					return err
				}
			}
		}
	}
```
(https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/crosschain/keeper/abci.go#L47-L49)
```go
func (k Keeper) CheckAndUpdateCctxGasPrice(
	ctx sdk.Context,
	cctx types.CrossChainTx,
	flags observertypes.GasPriceIncreaseFlags,
) (math.Uint, math.Uint, error) {
...
        //@audit this withdraw gas token from gas stability pool and will return error(NotEnoughFunds) if there is not enough balance in the pool
|>	if err := k.fungibleKeeper.WithdrawFromGasStabilityPool(ctx, chainID, additionalFees.BigInt()); err != nil {
		return math.ZeroUint(), math.ZeroUint(), cosmoserrors.Wrap(
			types.ErrNotEnoughFunds,
			fmt.Sprintf("cannot withdraw %s from gas stability pool", additionalFees.String()),
		)
	}
```
(https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/crosschain/keeper/abci.go#L107-L110)

As seen above, when one iteration return an error `NotEnoughFunds` the for-loop and the funciton will exit, skipping the remaining iteration.
## Tools Used
Manual review

## Recommended Mitigation Steps
In the for-loop, do not exit when one iteration returns an error, simply continue to the next iteration.


## Assessed type

Other
MAX_DEADLINE not flexible
Audit: 2023-11-zetachain-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/main/repos/protocol-contracts/contracts/evm/tools/ZetaTokenConsumerUniV3.strategy.sol#L29


# Vulnerability details

## Impact
Detailed description of the impact of this finding.
MAX_DEADLINE: The contract uses a constant MAX_DEADLINE for transaction deadlines, which may not be flexible enough for all users and use cases.

## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.
 
  uint256 internal constant MAX_DEADLINE = 200;

## Tools Used
Manual Analysis
## Recommended Mitigation Steps


## Assessed type

Context
Contract Inheritance  no inherit  from ZetaTokenConsumer
Audit: 2023-11-zetachain-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/main/repos/protocol-contracts/contracts/evm/tools/ZetaTokenConsumerUniV3.strategy.sol#L27


# Vulnerability details

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

Contract Inheritance: The contract is supposed to inherit from ZetaTokenConsumer, but the code for this base contract is not provided. It's important to review the base contract as well for any additional security considerations.

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

contract ZetaTokenConsumerUniV3 is ZetaTokenConsumer, ZetaTokenConsumerUniV3Errors {

## Tools Used
Manual Analysis
## Recommended Mitigation Steps
we should inherit from ZetaTokenConsumer


## Assessed type

Context
Incorrect Slash amount deducted
Audit: 2023-11-zetachain-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/main/repos/node/x/emissions/abci.go#L106
https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/observer/types/ballot.go#L88


# Vulnerability details

## Impact
Even if Observer failed to vote on multiple matured Ballot, only basic slashing amount would be deducted. 

## Proof of Concept
1. Lets say there were 10 ballots created for multiple transactions
2. Observer B fails to vote in any of them
3. Reward distribution happens using `DistributeObserverRewards` function which calculates reward units for each observer using `BuildRewardsDistribution` function
4. Since Observer B failed to all 10 ballots so `BuildRewardsDistribution` gives `rewardsMap[B]=-10`

```
case BallotStatus_BallotFinalized_SuccessObservation:
		for _, address := range m.VoterList {
			vote := m.Votes[m.GetVoterIndex(address)]
			if vote == VoteType_SuccessObservation {
				rewardsMap[address] = rewardsMap[address] + 1
				totalRewardUnits++
				continue
			}
			rewardsMap[address] = rewardsMap[address] - 1
		}
```

5. Now the reward distribution logic for negative reward is below:

```
if observerRewardUnits < 0 {
			slashAmount := keeper.GetParams(ctx).ObserverSlashAmount
			keeper.SlashObserverEmission(ctx, observerAddress.String(), slashAmount)
			finalDistributionList = append(finalDistributionList, &types.ObserverEmission{
				EmissionType:    types.EmissionType_Slash,
				ObserverAddress: observerAddress.String(),
				Amount:          slashAmount,
			})
			continue
		}
```

6. As we can see above only `slashAmount` is slashed from Observer even though he failed voting any ballot. Ideally slashAmount should be multiplied with the number of missed ballots to properly penalize the observer

## Tools Used

## Recommended Mitigation Steps
The slashing amount for defaulter Observer should be calculated as `(observerRewardUnits)*slashAmount`


## Assessed type

Other
Lack of Input Validation 
Audit: 2023-11-zetachain-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/main/repos/protocol-contracts/contracts/evm/tools/ZetaTokenConsumerTrident.strategy.sol#L68


# Vulnerability details

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

Lack of Input Validation: The getPair function assumes that the pool factory will return a valid pool address without validating the input tokens or the returned pool address.


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


 function getPair(address token0, address token1) internal pure returns (address, address) {
        if (token0 < token1) return (token0, token1);

        return (token1, token0);
    }


## Tools Used

## Recommended Mitigation Steps


## Assessed type

Invalid Validation
zero-value ERC20 token transfers can revert for   certain tokens
Audit: 2023-11-zetachain-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-zetachain/tree/main/repos/protocol-contracts/contracts/evm/ERC20Custody.sol#L181
https://github.com/code-423n4/2023-11-zetachain/tree/main/repos/protocol-contracts/contracts/evm/ERC20Custody.sol#L197


# Vulnerability details

## Impact
Some ERC20 tokens revert for zero-value transfers (e.g. `LEND`).
See [Weird ERC20 Tokens - Revert on Zero Value Transfers](https://github.com/d-xo/weird-erc20#revert-on-zero-value-transfers)

## Proof of Concept
```solidity
File: repos/protocol-contracts/contracts/evm/ERC20Custody.sol

181:         asset.safeTransferFrom(msg.sender, address(this), amount);

197:         IERC20(asset).safeTransfer(recipient, amount);

```

[181](https://github.com/code-423n4/2023-11-zetachain/tree/main/repos/protocol-contracts/contracts/evm/ERC20Custody.sol#L181), [197](https://github.com/code-423n4/2023-11-zetachain/tree/main/repos/protocol-contracts/contracts/evm/ERC20Custody.sol#L197)
## Tools Used
Manual Review
## Recommended Mitigation Steps


## Assessed type

ERC20
`AddBlockHeader` Cannot Cope with Reorgs
Audit: 2023-11-zetachain-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/observer/keeper/msg_server_add_block_header.go#L14


# Vulnerability details

## Impact

`AddBlockHeader` handles adding a block header to the node's store, through majority voting of observers. Reorgs happen, at different rates and depths for different chains and network conditions, but they do happen. And not only defensive measures must be taken to deal with them, but also remediation measures in case they occur more aggressively than expected. The problem is that a critical function to remove or reorganise the blocks is somehow missing from the external interface.

This submission is not about the estimation of financial loss or impact of reorgs, but the clear technical fact that blocks cannot be removed out of the store or somehow reorganised in case of emergency.

## Proof of Concept

The [`AddBlockHeader` function](https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/observer/keeper/msg_server_add_block_header.go#L14) is only called by observers after a certain number of confirmations is reached in the clients; [2 for Bitcoin](https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/observer/types/core_params_mainnet.go#L44), [14 for Ethereum](https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/observer/types/core_params_mainnet.go#L18), and [14 for BSC](https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/observer/types/core_params_mainnet.go#L31). As I intend to submit this topic in a Low/QA report, in this submission I will ignore that I find those confirmation numbers dangerously low for a software like ZetaChain.

Though, even if we consider that chances of reorgs past those confirmation numbers are low, they occur. And when they do occur beyond the expected safety parameters, and depending on the reorg depth, ZetaChain cannot possibly avoid the resultant financial damage. But there must be a plan in place and critical functions available to deal with the necessary actions to guarantee operational continuity. And none could be found. There is only a keeper function [`RemoveBlockHeader`](https://github.com/code-423n4/2023-11-zetachain/blob/b237708ed5e86f12c4bddabddfd42f001e81941a/repos/node/x/observer/keeper/block_header.go#L37), but, oddly, this is not used anywhere in the codebase.

Currently, ZetaChain cannot operate normally if there is need to remove or reorganise some block(s) in the store. For example, suppose there is a reorg beyond the clients' (very minimal) safety parameters and the block headers have already been added. Financial damage may be inevitable, but observers should be able to vote on a solution to the conundrum so ZetaChain can continue to extend its consensus about the connected ch