xanoutas/solidity-security-findings huggingface dataset:
Lack of Validation for 'destinationAddress' in 'transmitSendToken' Function May Lead to Failed Transactions
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/its/interchain-token-service/InterchainTokenService.sol#L502-L523


# Vulnerability details

## Impact
During cross-chain transactions, the address on the `destinationChain`, i.e., the `destinationAddress`, is a crucial factor since it is where the tokens will be sent to. Therefore, if this address is invalid, the transaction would fail because the tokens cannot be correctly sent to the intended recipient.

## Proof of Concept
[InterchainTokenService.sol#L502-L523](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/its/interchain-token-service/InterchainTokenService.sol#L502-L523)

```
    function transmitSendToken(
        bytes32 tokenId,
        address sourceAddress,
        string calldata destinationChain,
        bytes memory destinationAddress,
        uint256 amount,
        bytes calldata metadata
    ) external payable onlyTokenManager(tokenId) notPaused {
        bytes memory payload;
        if (metadata.length < 4) {
            payload = abi.encode(SELECTOR_SEND_TOKEN, tokenId, destinationAddress, amount);
            _callContract(destinationChain, payload, msg.value, sourceAddress);
            emit TokenSent(tokenId, destinationChain, destinationAddress, amount);
            return;
        }
        uint32 version;
        (version, metadata) = _decodeMetadata(metadata);
        if (version > 0) revert InvalidMetadataVersion(version);
        payload = abi.encode(SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destinationAddress, amount, sourceAddress.toBytes(), metadata);
        _callContract(destinationChain, payload, msg.value, sourceAddress);
        emit TokenSentWithData(tokenId, destinationChain, destinationAddress, amount, sourceAddress, metadata);
    }
```
In the `transmitSendToken` function, we see that the `destinationAddress` is used directly to construct the transaction payload and then executed on the destination chain. However, there isn't a check for the validity of the `destinationAddress` before sending it. This means that if the function caller provides an invalid address, the transaction would fail during execution, wasting gas and potentially blocking other valid transactions.

## Recommended Mitigation Steps
To address this issue, one possible solution could be to validate the `destinationAddress`'s validity before sending the transaction. This could involve calling some service on the destination chain to check if the address exists or at least ensure that the address complies with the expected format and length. This could prevent transaction failures due to invalid addresses, thereby enhancing the robustness and security of the smart contract.


## Assessed type

Invalid Validation
External calls in loop in function `setFlowLimit` can lead to denial of service
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/its/interchain-token-service/InterchainTokenService.sol#L534-L541


# Vulnerability details

## Impact
In smart contracts, Calls to external contracts inside a loop are dangerous (especially if the loop index can be user-controlled) because they could lead to DoS if one of the calls reverts or execution runs out of gas.

## Proof of Concept

```
    function setFlowLimit(bytes32[] calldata tokenIds, uint256[] calldata flowLimits) external onlyOperator {
        uint256 length = tokenIds.length;
        if (length != flowLimits.length) revert LengthMismatch();
        for (uint256 i; i < length; ++i) {
            ITokenManager tokenManager = ITokenManager(getValidTokenManagerAddress(tokenIds[i]));
            tokenManager.setFlowLimit(flowLimits[i]);
        }
    }
```

In the `setFlowLimit` function, the code calls the `setFlowLimit` function of the external `ITokenManager` contract within a loop. This function could possibly `revert` or consume a significant amount of gas. If the length of the `tokenIds` and `flowLimits` arrays can be controlled by the user, an attacker might attempt to construct a very large array in an attempt to exhaust the contract's gas. If successful, this would render the contract unusable and result in a Denial of Service (DoS) state.

## Recommended Mitigation Steps

To prevent this from happening, smart contract developers typically take measures such as limiting the number of loop iterations or ensuring that the number of loop iterations cannot be directly controlled by users. In the `setFlowLimit` function, some checks should be added to ensure that the length of the `tokenIds` and `flowLimits` arrays is within a safe range.


## Assessed type

DoS
Malicious `newImplementation` address can alter the governance of the `AxelarGateway` contract
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/AxelarGateway.sol#L284
https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/AxelarGateway.sol#L294


# Vulnerability details

## Impact
- `AxelarGateway` contract has upgrade functionality where a `newImplementation` of the `AxelarGateway` can be set, and it's only accessible by the governor (protected by `onlyGovernance` modifier).
- The vulnerability arises from the `delegatecall` used in the `upgrade` function; this can harm the gateway in the following scenario:
  since the `delegatecall` opcode is used to setup the `newImplemenation` address; a malicious `newImplementation` contract address can use the `tx.origin` (which is the EOA of the gateway governor) to set up a new governor address.

- This will result in stealing the governance of the `AxelarGateway` contract, so the upgradeability of the gateway will be controlled by the new malicious governer;where he can set a `newImplementation` contract with malicious functionalities & variables.

## Proof of Concept

[AxelarGateway.sol/upgrade function/Line 284](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/AxelarGateway.sol#L284)

```solidity
Line 284: ) external override onlyGovernance {
```

[AxelarGateway.sol/upgrade function/Line 294](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/AxelarGateway.sol#L294)

```solidity
Line 294: (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(IAxelarGateway.setup.selector, setupParams));
```

## Tools Used

Manual Testing.

## Recommended Mitigation Steps

Update the `upgarde` function to revert if, after the `delegatecall`, the governor account is not the original one,this can be achieved by adding the following code to the `upgrade` function after checking the `delegatecall` success :

```solidity
address originalGovernance=getAddress(KEY_GOVERNANCE);// added before the delegatecall
//......
if (originalGovernance != getAddress(KEY_GOVERNANCE)) revert NotGovernance();// added after the delegatecall
```





## Assessed type

call/delegatecall
Malicious `newImplementation` address can selfdestruct the `AxelarGateway` contract
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/AxelarGateway.sol#L294


# Vulnerability details

## Impact
- `AxelarGateway` contract has upgrade functionality where a `newImplementation` of the `AxelarGateway` can be set.
- The vulnerability arises from the `delegatecall` used in the `upgrade` function; this can harm the gateway in the following scenario:
  a malicious suicidal `newImplementation` contract address with a fallback that has a selfdestruct logic in it(when the newImplementation contract doesn't have a `setup` function)/or with a selfdestruct logic being set in the newImplementation contract `setup` function can be used to destruct the `AxelarGateway` contract, as per the code below:

  ```solidity
  contract MaliciousNewImplementation {
    fallback() external {
        selfdestruct(payable(0));
    }
  }
  ```

  or it can have a suicidal setup function:

  ```solidity
  contract MaliciousNewImplementation {
  function setup(bytes calldata params) external {
  selfdestruct(payable(0));
  }
  }
  ```
- This will lead to the destruction of `AxelarGateway` contract; which would result in freezing all the functionalities that point to such an implementation

## Proof of Concept

[AxelarGateway.sol/upgrade function/Line 294](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/AxelarGateway.sol#L294)

```solidity
File: contracts/cgp/AxelarGateway.sol
Line 294: (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(IAxelarGateway.setup.selector, setupParams));
```

## Tools Used

Manual Testing.

## Recommended Mitigation Steps

Deploy `AxelarGateway.sol` via CREATE2 so it can be redeployed if destructed by a malicious `newImplementation` contract.


## Assessed type

call/delegatecall
`onlySigners` modifier will not revert if the proposal hasn't met the threshold voting which results in funds being locked
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/auth/MultisigBase.sol#L44-L77
https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/governance/Multisig.sol#L30-L34
https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/governance/AxelarServiceGovernance.sol#L48-L52


# Vulnerability details

## Impact
- In `MultisigBase.sol`/`onlySigners` modifier: this modifier is meant by design to be used for voting on topics/proposals and for granting access for the last signer who will make the votes count on a specific proposal passes the threshold.
- And this modifier reverts in two cases only: when a non-signer tries to access the protected function, or when a signer has already voted on the topic/proposal.
- So if a signer that hasn't voted yet on a specific topic/proposal tries to execute a proposal with a `msg.value` ; it will not revert if the threshold hasn't been met yet (the modifier will return); and this will result in locking any `msg.value` being sent.

## Proof of Concept

- [MultisigBase.sol/onlySigners modifier](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/auth/MultisigBase.sol#L44-L77)

```solidity
File:contracts/cgp/auth/MultisigBase.sol
Line 44-77:
    modifier onlySigners() {
        if (!signers.isSigner[msg.sender]) revert NotSigner();

        bytes32 topic = keccak256(msg.data);
        Voting storage voting = votingPerTopic[signerEpoch][topic];

        // Check that signer has not voted, then record that they have voted.
        if (voting.hasVoted[msg.sender]) revert AlreadyVoted();

        voting.hasVoted[msg.sender] = true;

        // Determine the new vote count.
        uint256 voteCount = voting.voteCount + 1;

        // Do not proceed with operation execution if insufficient votes.
        if (voteCount < signers.threshold) {
            // Save updated vote count.
            voting.voteCount = voteCount;
            return; // @audit : the line of the bug
        }

        // Clear vote count and voted booleans.
        voting.voteCount = 0;

        uint256 count = signers.accounts.length;

        for (uint256 i; i < count; ++i) {
            voting.hasVoted[signers.accounts[i]] = false;
        }

        emit MultisigOperationExecuted(topic);

        _;
    }
```

- [Multisig.sol/execute function](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/governance/Multisig.sol#L30-L34)

```solidity
File:contracts/cgp/governance/Multisig.sol
Line 30-34:
    function execute(
        address target,
        bytes calldata callData,
        uint256 nativeValue
    ) external payable onlySigners {
```

- [AxelarServiceGovernance.sol/executeMultisigProposal function](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beaf
Not checking if `nativeValue` equals to `msg.value` leads to funds drainage
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/governance/Multisig.sol#L30-L36
https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/governance/InterchainGovernance.sol#L68-L79
https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/governance/AxelarServiceGovernance.sol#L48-L62


# Vulnerability details

## Impact
- In `Multisig.sol`/`execute` function: the function is payable ,and the amount of native tokens to be sent with the call is `nativeValue`, but there's no check if `nativeValue` equals to the `msg.value` that is sent with the function call,
- This can be used to send the target contract a `nativeValue` greater than the `msg.value`; which will lead to funds drainage.
- So if there's locked balance in the contract; it will be drained by not checking if `nativeValue > msg.value`.
- The same vulnerability is spotted in `executeProposal` function in `InterchainGovernance.sol` &
  in `executeMultisigProposal` function in `AxelarServiceGovernance.sol`.
- This will lead to drainage of contracts funds.

## Proof of Concept

- [Multisig.sol/execute function](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/governance/Multisig.sol#L30-L36)

```solidity
File:contracts/cgp/governance/Multisig.sol
Line 30-36:
    function execute(
        address target,
        bytes calldata callData,
        uint256 nativeValue
    ) external payable onlySigners {
        _call(target, callData, nativeValue);
    }
```

- [InterchainGovernance.sol/executeProposal function](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/governance/InterchainGovernance.sol#L68-L79)

```solidity
File:contracts/cgp/governance/InterchainGovernance.sol
Line 68-79:
    function executeProposal(
        address target,
        bytes calldata callData,
        uint256 nativeValue
    ) external payable {
        bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue));


        _finalizeTimeLock(proposalHash);
        _call(target, callData, nativeValue);


        emit ProposalExecuted(proposalHash, target, callData, nativeValue, block.timestamp);
    }
```

- [AxelarServiceGovernance.sol/executeMultisigProposal function](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/governance/AxelarServiceGovernance.sol#L48-L62)

```solidity
File:contracts/cgp/governance/AxelarServiceGovernance.sol
Line 48-62:
    function executeMultisigProposal(
        address target,
        bytes calldata callData,
        uint256 nativeValue
    ) external payable onlySigners {
        bytes32 proposalHash = keccak256(abi.encodePacked(target, callData, nativeValue));


        if (!multisigApprovals[proposalHash]) revert NotApproved();
Any signer can unlock any function protected by `onlySigners` modifier by sending a `msg.data` of a nearly winning proposal
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/auth/MultisigBase.sol#L44-L77
https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/auth/MultisigBase.sol#L142-L144
https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/governance/Multisig.sol#L30-L36


# Vulnerability details

## Impact
- In `MultisigBase.sol`/`onlySigners` modifier: this modifier is meant by design to allow access for signers **after** a voting on a specific topic/proposal succeeds (when voteCount >= signers.threshold).
- So this will give access to the **last signer** who will make the voting succeed; after that the votes on this topic/proposal is cleared.
- So any malicious signer can track any topic/proposal that needs only one vote to pass by tracking the `votingPerTopic`,and then access any function that's locked by `onlySigners` modifier by sending a `msg.data` similar to the topic that needs one vote to succeed .
- This vulnerability arises since there's no mechanism to check if the `msg.data` sent is similar to the called function arguments.  

**Note: nearly winning proposal means a proposal that needs only one vote to be executed**  
- This vulnerability can be used to exploit different functions:
  1. Any malicious signer can change the signers and threshold (`rotateSigners`) by passing a `msg.data` of any nearly winning topic/proposal (so the `rotateSigners` function can be accessed).
  2. In `Mulitisig.sol`/`execute` function : any malicious proposal can be executed by passing a `msg.data` of a nearly winning proposal, so the malicious proposal will be executed even if it doesn't have any votes on it/or the votes on it is less than the threshold.
## Proof of Concept

- [MultisigBase.sol/onlySigners modifier](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/auth/MultisigBase.sol#L44-L77)

```solidity
File:contracts/cgp/auth/MultisigBase.sol
Line 44-77:
    modifier onlySigners() {
        if (!signers.isSigner[msg.sender]) revert NotSigner();

        bytes32 topic = keccak256(msg.data); //@audit
        Voting storage voting = votingPerTopic[signerEpoch][topic];

        // Check that signer has not voted, then record that they have voted.
        if (voting.hasVoted[msg.sender]) revert AlreadyVoted();

        voting.hasVoted[msg.sender] = true;

        // Determine the new vote count.
        uint256 voteCount = voting.voteCount + 1;

        // Do not proceed with operation execution if insufficient votes.
        if (voteCount < signers.threshold) {
            // Save updated vote count.
            voting.voteCount = voteCount;
            return;
        }

        // Clear vote count and voted booleans.
        voting.voteCount = 0;

        uint256 count = signers.accounts.length;

        for (uint256 i; i < count; ++i) {
AxelarGateway::setup can be called by anyone
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/cgp/AxelarGateway.sol#L307-L321


# Vulnerability details

## Impact
AxelarGateway::setup is not checked, anyone can call this function to modify state variables

```solidity
function setup(bytes calldata params) external override {//@audit 任何人可以调用
        // Prevent setup from being called on a non-proxy (the implementation).
        if (implementation() == address(0)) revert NotProxy();

        (address governance_, address mintLimiter_, bytes memory newOperatorsData) = abi.decode(params, (address, address, bytes));

        if (governance_ != address(0)) _transferGovernance(governance_);
        if (mintLimiter_ != address(0)) _transferMintLimiter(mintLimiter_);

        if (newOperatorsData.length != 0) {
            IAxelarAuth(AUTH_MODULE).transferOperatorship(newOperatorsData);

            emit OperatorshipTransferred(newOperatorsData);
        }
    }
```



## Proof of Concept

```js
// test/cgp/AxelarGateway.js
it('should not allow calling the setup function directly', async () => {
    const newOperatorAddresses = getAddresses(operators.slice(0, 2));

    const params = getWeightedProxyDeployParams(governance.address, mintLimiter.address, newOperatorAddresses, Array(2).fill(1), 2);

   
    await expect(gateway.connect(wallets[10]).setup(params)).not.to.emit(gateway, 'OperatorshipTransferred');

});
```

## Tools Used
vscode
## Recommended Mitigation Steps

```diff
- function setup(bytes calldata params) external override {
+ function setup(bytes calldata params) external override  onlyGovernance {
```


## Assessed type

Access Control
the function `transmitSendToken` did not handle the metadata.length equal to 4 correctly which may lead to unexpected behavior
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/its/interchain-token-service/InterchainTokenService.sol#L502-L523
https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/its/interchain-token-service/InterchainTokenService.sol#L872-L878


# Vulnerability details

## Impact

in the function `transmitSendToken` in `InterChainTokenService.sol` there is a check for the metadata, this check set to make sure if the `metaData < 4` then a logic will be run that can handle length of 3 of the metaData.length by encode specific params, but if the `MetaData.length >= 4` then the call to the `_decodeMetadata` happen, the problem is if the metadata length was equal to 4 then unexpected behavior may happen because of the `sub` and `add` that is used in the `_decodeMetadata`. more details in POC

## Proof of Concept

the function `transmitSendToken` will call the `_decodeMetadata` if the metadata length is more or equal to 4:

```solidity
function transmitSendToken(
    bytes32 tokenId,
    address sourceAddress,
    string calldata destinationChain,
    bytes memory destinationAddress,
    uint256 amount,
    bytes calldata metadata
) external payable onlyTokenManager(tokenId) notPaused {
    bytes memory payload;
    if (metadata.length < 4) {
        payload = abi.encode(SELECTOR_SEND_TOKEN, tokenId, destinationAddress, amount);
        _callContract(destinationChain, payload, msg.value, sourceAddress);
        emit TokenSent(tokenId, destinationChain, destinationAddress, amount);
        return;
    }
    uint32 version;
    //@audit
    (version, metadata) = _decodeMetadata(metadata);
    if (version > 0) revert InvalidMetadataVersion(version);
    payload = abi.encode(SELECTOR_SEND_TOKEN_WITH_DATA, tokenId, destinationAddress, amount, sourceAddress.toBytes(), metadata);
    _callContract(destinationChain, payload, msg.value, sourceAddress);
    emit TokenSentWithData(tokenId, destinationChain, destinationAddress, amount, sourceAddress, metadata);
}

```

and the function `_decodeMetadata` is this:

```
 function _decodeMetadata(bytes calldata metadata) internal pure returns (uint32 version, bytes calldata data) {
        assembly {
            //@audit
            data.length := sub(metadata.length, 4)
            data.offset := add(metadata.offset, 4)
            version := calldataload(sub(metadata.offset, 28))
        }
    }
```

lets imagine that the `metadata.length` is only four, then the `_decodeMetadata` will handle this like that:

```
assembly {
   data.length := sub(4, 4) // which it equal zero (sub them)
   data.offset := add(metadata.offset, 4) // return 4 in this case
 version := calldataload(sub(, 28))

}
```

let break this code line by line:

1- first Since `metadata.length` is 4 and we subtract 4 from it, data.length will be set to 0. This means the data variable will have a length of 0.

2-since the length of `data` is 0, th