xanoutas/solidity-security-findings huggingface dataset:
Attacker can steal funcds from `InterchainProposalExecutor` contract
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/interchain-governance-executor/InterchainProposalSender.sol#L38
https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L22


# Vulnerability details

## Impact
In `InterchainProposalSender` users can send proposals to diffrent chains by passing the call data `InterchainCalls.Call` into `sendProposals` or `sendProposal` functions, this struct contains another struct `Call` which contains target, value and call data, but these payable functions doesn't check the `msg.value` with `value` to see if sender sent the value that they want to send to destination chain, it just checks the `msg.value` for the gas they want to send not the value.

since the sent proposals can be executed in `InterchainProposalExecutor` contract by callers and the `_executeProposal` function sends the value to target address this contract's balance can be stolen

## Proof of Concept
here is the `_sendPropsal` functions which doesn't check for `msg.value` 

```solidity
    function _sendProposal(InterchainCalls.InterchainCall memory interchainCall) internal {
        bytes memory payload = abi.encode(msg.sender, interchainCall.calls);

        if (interchainCall.gas > 0) {
            gasService.payNativeGasForContractCall{ value: interchainCall.gas }(
                address(this),
                interchainCall.destinationChain,
                interchainCall.destinationContract,
                payload,
                msg.sender
            );
        }

        gateway.callContract(interchainCall.destinationChain, interchainCall.destinationContract, payload);
    }
```

## Recommended Mitigation Steps
in `sendProposals` which calls `revertIfInvalidFee` function you should also check for values

The function should look like this
```
    function revertIfInvalidFee(InterchainCalls.InterchainCall[] calldata interchainCalls) private {
        uint256 totalGas = 0;
        uint256 totalValue = 0;
        for (uint256 i = 0; i < interchainCalls.length; ) {
            totalGas += interchainCalls[i].gas;
            totalValue += interchainCalls[i].calls.value;
            unchecked {
                ++i;
            }
        }

        if (totalGas + totalValue != msg.value) {
            revert InvalidFee();
        }
    }
```

in `sendProposal` you can check for it as same but insted only for one proposal.


## Assessed type

Invalid Validation
Malicious user can permanently break InterchainProposalExecutor#_executeProposal by returning huge amounts of data
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/interchain-governance-executor/InterchainProposalExecutor.sol#L76


# Vulnerability details

## Impact
InterchainProposalExecutor#_executeProposal makes a call to interchaincall to send the value. It then stores the return data of the call in memory. A malicious user could set the interchaincall target to a malicious contract that would return an extremely large data amount that would guaranteed cause an OOG error when loaded to memory. The result is that would be permanently locked causing massive loss

## Proof of Concept
see impact 
## Tools Used
manuel 
## Recommended Mitigation Steps
Cap the data returned or don't store the return data at all




## Assessed type

call/delegatecall
funds can be stolen in `InterchainGovernance`, `Multisig` and `AxelarServiceGovernance` contracts
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact

In `InterchainGovernance` users can execute the proposal by passing required data and the amount of native value they want to send with `executeProposal` function, this function calls [`_call`](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/util/Caller.sol#L11) function in Caller contract, but this function insted of checking `msg.value` it checks to see if current balance of contract is greater than the arbitrary `nativeValue` passed to function. So this means they can steal funds from contract without sending any value to the contract and set the `nativeValue` amount to balance of the contract.

In `Multisig.sol::execute` and `AxelarServiceGovernance.sol::executeMultisigProposal` it's also the same scenario insted only signers are allowed to call the functions.

## Proof of Concept
Here is the `_call` function in Caller contract which checks the current balance of the contract

```solidity
    function _call(
        address target,
        bytes calldata callData,
        uint256 nativeValue
    ) internal {
        if (nativeValue > address(this).balance) revert InsufficientBalance();

        (bool success, ) = target.call{ value: nativeValue }(callData);
        if (!success) {
            revert ExecutionFailed();
        }
    }
```

## Tools Used
Manual Review

## Recommended Mitigation Steps

You should check to see if `msg.value` is equal to `nativeValue`.

`if (nativeValue != msg.value) revert InsufficientBalance();`


## Assessed type

Invalid Validation
Honest users could lose funds due to the current implementation of `executeProposal()`
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details


## Impact

In the [InterChainGovernance.sol](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/governance/InterchainGovernance.sol) contract, the `executeProposal` function lacks an explicit check to ensure that the `msg.value` provided with the function call is greater than or equal to the `nativeValue` specified.

After an extensive discussion with the sponsors, we came to an conclusion that

> If less amount is provided in `executeProposal()` and for some reason there is still enough balance in the contract then the function will not revert. This allows for the msg.value to be sent along with the caller, or for _some other entity_ to pay for the call by simply funding the contract right before the caller executes the proposal. Note the _payable receive function found_ at the bottom of the contract.

This potential oversight easily leads to possible front-running attacks, where an attacker can observe pending transactions and then scoop up the funds in the contract to execute their transactions ahead of honest users, _see POC_.

## Proof of Concept

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

```solidity
    /**
     * @notice Executes a proposal
     * @dev The proposal is executed by calling the target contract with calldata. Native value is
     * transferred with the call to the target contract.
     * @param target The target address of the contract to call
     * @param callData The data containing the function and arguments for the contract to call
     * @param nativeValue The amount of native token to send to the target contract
     //@audit there is no explicit checks to ensure that the msg.value provided with the function call is >= the nativeValue specified
     */
    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);
    }


```

Here is a hypothetical PoC scenario:

1. A legitimate user (Alice) funds the contract.
2. Alice then tries to call the `executeProposal()` function to forward their native value to a target contract.
3. An attacker (Bob) is watching the mempool for any queries to this function.
4. Seeing Alice's transaction, Bob also calls the function with a higher gas fee and a new target address. This allows Bob's transaction to be mined before Alice's.
5. As a result,
`onlyProxy` MODIFIER CAN BE BYPASSED BY A MALICIOUS PROXY CONTRACT AND CAN PUSH THE IMPLEMENTATION CONTRACT INTO AN UNDESIRABLE STATE
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/gmp-sdk/upgradable/Upgradable.sol#L29-L33
https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/gmp-sdk/upgradable/Upgradable.sol#L78-L80
https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/gmp-sdk/upgradable/Proxy.sol#L40-L43


# Vulnerability details

## Impact

The `Upgradeable.onlyProxy` modifier is used to ensure that a function can only be called by the proxy and can not be directly called in the `Upgradeable.sol` contract. 

The `onlyProxy` modifier implementation is as follows:

    modifier onlyProxy() {
        // Prevent setup from being called on the implementation
        if (address(this) == implementationAddress) revert NotProxy();
        _;
    }

Only the proxy contract can call a function guarded this modifier via a `delegatecall`. If directly called this modifier will revert the transaction.

This modifier is used in the `Upgradeable.setup` function. The `setup` function is used to setup the `implementation` contract with initial data. 

The problem here is that a malicious user can create his own `Proxy Contract` and `delegatecall` the implementation contract by calling its `Upgradeable.setup` function. This way he can bypass the `onlyProxy` modifier since now the `address(this) == implementationAddress` condition will be false and the transaction will execute.

This issue is aggravated since there is no `initializer` modifier (from openzeppelin) in the `Upgradeable.setup` function. Hence this function can be called multiple times.

As a result the malicious user can use the above vulnerabilities to `delegatecall` the `Upgradeable.setup` with his own `setupParams` (after the `setup` is called via the `Proxy.constructor`) and change the state of the implementation contract and push it into an undesirable state.

For example the `InterchainTokenService` contract inherits from `Upgradeable` contract. The `InterchainTokenService._setup` function is used to call the `Operatable._setOperator` function to set the `operator_` address of the `InterchainTokenService`. Hence an attacker can use the above mentioned attack path to set the `operator` to a malicious address and control the `InterchainTokenService.setFlowLimit` function (controlled by `onlyOperator` modifier) to set his own flow limits for token managers thus violating the contract state.

Thus the users who use this compromised implementation contract will be susceptible to undesirable transactions.

## Proof of Concept

```solidity
    modifier onlyProxy() {
        // Prevent setup from being called on the implementation
        if (address(this) == implementationAddress) revert NotProxy();
        _;
    }
```

https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/gmp-sdk/upgradable/Upgradable.sol#L29-L33

```solidity
    function setup(bytes calldata data) external override onlyProxy {
        _setup(data);
    }
```

https://github.com/code-423n4/2023-07
Risk of Rogue Signer Control: Potential for Malicious Signer to Modify Threshold and Gain Unauthorized Control of Multisig Contract
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/374cbd0c78b84fee8b7ea0c813a33b3354173f06/contracts/cgp/auth/MultisigBase.sol#L135-L144
https://github.com/code-423n4/2023-07-axelar/blob/374cbd0c78b84fee8b7ea0c813a33b3354173f06/contracts/cgp/auth/MultisigBase.sol#L146-L179


# Vulnerability details

## Impact
The "Rotation of Signers" mechanism in the Multisig contract poses a risk of a single rogue or compromised signer gaining unauthorized control of the contract. If a signer with malicious intent or compromised credentials utilizes the `rotateSigners` function, they could potentially modify the list of authorized signers, setting the threshold to 1, and adding only themselves to the updated list. This would grant them full control over the multisig contract, bypassing the need for further approvals.

## Proof of Concept
// Below is a Proof of Concept (PoC) to demonstrate the vulnerability of the "Rotation of Signers" mechanism and the potential risk it poses.
// It requires the attacker/rogue signer to already have onlySigners access or to gain access somehow, therefore this vulnerability is more likely to be exploited(but not exclusively) by a "trusted" rogue signer.

// Attacker contract to exploit the vulnerability
contract Attacker {
    Multisig public multisig;

    constructor(address _multisigAddress) {
        multisig = Multisig(_multisigAddress);
    }

    // Function to execute the attack
    function executeAttack() external {
        // Craft a malicious array containing only the attacker's address
        address[] memory maliciousAccounts = new address[](1);
        maliciousAccounts[0] = msg.sender;

        // Set the threshold to 1 to bypass the requirement of multiple signers
        uint256 threshold = 1;

        // Call the rotateSigners function with the malicious parameters
        multisig.rotateSigners(maliciousAccounts, threshold);
    }
}

// Contract with the vulnerable "Rotation of Signers" mechanism
contract Multisig {
    struct Signers {
        address[] accounts;
        mapping(address => bool) isSigner;
        uint256 threshold;
    }

    Signers public signers;
    uint256 public signerEpoch;

    modifier onlySigners() {
        require(signers.isSigner[msg.sender], "Not a signer");
        _;
    }

    event SignersRotated(address[] newAccounts, uint256 newThreshold);

    function rotateSigners(address[] memory newAccounts, uint256 newThreshold) external virtual onlySigners {
        _rotateSigners(newAccounts, newThreshold);
    }

    function _rotateSigners(address[] memory newAccounts, uint256 newThreshold) internal {
        uint256 length = signers.accounts.length;

        // Clean up old signers.
        for (uint256 i; i < length; ++i) {
            signers.isSigner[signers.accounts[i]] = false;
        }

        length = newAccounts.length;

        if (newThreshold > length) revert("Invalid signers");
        if (newThreshold == 0) revert("Invalid signer threshold");
Insecure minimum threshold in `_rotateSigners` function
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#L161


# Vulnerability details

## Impact
Insecure minimum threshold in `_rotateSigners` function can cause execution of malicious multisig proposals with unexpected results.

## Proof of Concept
The [`_rotateSigners`](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/auth/MultisigBase.sol#L149-L180) is the only function which can initialize multisig parameters. This function has zero check for the `newThreshold` parameter, but it is not enough for reliable multisig.
```solidity
161:        if (newThreshold == 0) revert InvalidSignerThreshold();
```
There are a lot of examples of addresses compromising. Therefore multi signature should be initialized in a secure decentralized way to prevent malicious upgrades and proposals because of one or several addresses compromising.

## Tools Used
Manual review

## Recommended Mitigation Steps
I suggest following the CFT model equilibrium: `N >= 2f + 1`, where N - amount of signers, f - amount of compromised or silent addresses. So the threshold should save the equilibrium, and the threshold should be `N - f`.
When N = 1, f = 0, threshold is 1; 
N = 2, f = 0, threshold is 2; 
N = 3, f = 1, threshold is 2;
N = 4, f = 1, threshold is 3;
N = 5, f = 2, threshold is 3;
N = 6, f = 2, threshold is 4;
N = 7, f = 3, threshold is 4;
etc.
You can see that the current check is enough only for one signer. 




## Assessed type

Governance
StandardizedToken can be setup multiple times by anyone. Causing unlimited mint by anyone.
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/its/token-implementations/StandardizedToken.sol#L49-L68


# Vulnerability details

## Impact
StandardizedToken can be setup multiple times by anyone. Causing unlimited mint by anyone.

## Proof of Concept

```solidity
    function setup(bytes calldata params) external override onlyProxy {
        {
            address distributor_;
            address tokenManager_;
            string memory tokenName;
            (tokenManager_, distributor_, tokenName, symbol, decimals) = abi.decode(params, (address, address, string, string, uint8));
            _setDistributor(distributor_);
            tokenManager = tokenManager_;
            _setDomainTypeSignatureHash(tokenName);
            name = tokenName;
        }
        {
            uint256 mintAmount;
            address mintTo;
            (, , , , , mintAmount, mintTo) = abi.decode(params, (address, address, string, string, uint8, uint256, address));
            if (mintAmount > 0) {
                _mint(mintTo, mintAmount);
            }
        }
    }
```

This contract is using onlyProxy which has the following definition

Check that the execution is being performed through a delegatecall call and that the execution context is a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to fail.

It only prevent user from calling the implementation contract which shouldn't be used to prevent setup from calling multiple times or by anyone.

User normally execute through proxy and onlyProxy should always passed. Which mean anyone can call setup function and mint unlimited token.

## Tools Used
Manual review

## Recommended Mitigation Steps
Use initializer modifier from Openzeppelin instead of onlyProxy.

https://github.com/OpenZeppelin/openzeppelin-upgrades/blob/master/packages/core/contracts/Initializable.sol



## Assessed type

Access Control
Payable functions using delegatecall inside a loop
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/its/utils/Multicall.sol#L22-L33


# Vulnerability details

## Impact
The use of delegatecall within a loop, in the context of a payable function, can lead to the repeated crediting of the msg.value amount, potentially causing unexpected behavior or loss of funds.

## Proof of Concept
```solidity
contract DelegatecallInLoop is Multicall {

    mapping (address => uint256) public balances;

    function addBalance(address a) public payable {
        balances[a] += msg.value;
    } 

}
```

If addBalances() is called with multiple receivers, the same msg.value will be reused for each recipient even though the corresponding ETH for only one recipient is sent.

For example:
Pass the data `["0xb5cef24a00000000000000000000000078731d3ca6b7e34ac0f824c42a7cc18a495cabab", "0xb5cef24a0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4", "0xb5cef24a000000000000000000000000ab8483f64d9c6d1ecf9b849ae677dd3315835cb2"]` and the msg.value will be reflected in the balances of three accounts.


## Tools Used
Remix

## Recommended Mitigation Steps
Carefully check that the function called by delegatecall is not payable/doesn't use msg.value.


## Assessed type

call/delegatecall
Voter/caller's eth will be stuck in contracts if the proposal fails to pass
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L52
https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/cgp/governance/Multisig.sol#L34


# Vulnerability details

## Impact
Voters of AxelarServiceGovernance.sol:executeMultisigProposal() or callers of Multisig.sol:execute() will have their eth stuck in the contract if they can't make the proposal/call pass the vote count checks in onlySigners.

## Proof of Concept
AxelarServiceGovernance.sol:executeMultisigProposal() and callers of Multisig.sol:execute() are payable, allowing voters/callers to give their eth as the nativeValue if the proposal passed later.

In the onlySigners modifier, we will return earlier if the vote count hasn't increased to the threshold:

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

Finally, we don't give the voters the right to revoke and take their eth back.

The above conditions bring a situation where voters can get their eth stuck in contracts:

1. There are x voters, and the threshold is x - n.
2. A proposal request nativeValue is proposed by calling executeMultisigProposal(). x - n - 1 voters vote on the proposal and give their eth.
3. There are n + 1 voters who strongly disagree with this proposal, thus making eth stuck.

## Tools Used
Manual Review.

## Recommended Mitigation Steps
Record every voter's msg.value and give voters the right to revoke their vote/eth.



## Assessed type

ETH-Transfer
AxelarGateway.sol: external setup funtion allow anyone to set `governance_`, `mintLimiter_` and `operator` 
Audit: 2023-07-axelar-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
Anyone can call through the [setup](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/AxelarGateway.sol#L307-L321) function and pass the params to set the mintlimiter, operator and governance.

## Proof of Concept
https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/AxelarGateway.sol#L307-L321

As we can in above link, the setup function is called to set the mint limiter, operator and governance address.
As per natsc comment, it is overshadowed by the proxy contract.
But, since it has the external modifier, anyone can call this through proxy and set the some of the critical parameters as mentioned in issue title.

since the governor, operator and mint limiter are some of the critical factors, setting this by anybody could lead to unexpected consequence.

## Tools Used

## Recommended Mitigation Steps

Implement owner based access mechanism such that only the owner will be able to call the settup function.


## Assessed type

Access Control