xanoutas/solidity-security-findings huggingface dataset:
Replay Attack Vulnerability Due to Uniqueness Invariant Violation in AxelarServiceGovernance Contract's Proposal Hash Generation
Audit: 2023-07-axelar-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/9048517392e03720a0cd32d5b79db84f5e5f7c8e/contracts/cgp/governance/AxelarServiceGovernance.sol#L42-L62


# Vulnerability details

## Impact
The current implementation of the AxelarServiceGovernance contract relies solely on the Keccak256 algorithm to generate proposal hashes, using only the target contract's address, encoded function call data, and the native token transfer value as components. This poses a potential vulnerability as the uniqueness of each proposal hash is not guaranteed, making the system susceptible to replay attacks. An attacker could easily duplicate or resubmit previous proposals, leading to unintended or malicious actions being executed.

To mitigate the replay attack vulnerability, it is recommended to include the nonce and chain ID as additional components in the Keccak256 hash calculation for generating proposal hashes. By doing so, each proposal will have a unique cryptographic value, preventing replay attacks and ensuring the uniqueness of each proposal.

## Proof of Concept
To demonstrate the fix for the vulnerability and the mitigation of replay attacks, the contract should be updated to include the nonce and chain ID as additional components when computing the proposal hash. This way, each proposal submission will receive a unique cryptographic value that increments with each new submission, ensuring hash distinctiveness. Furthermore, including the chain ID ensures that proposals are specific to their intended blockchain network, making them invalid on different chains even if other components are replicated.

Update the Proposal Hash Calculation Function:

function _calculateProposalHash(
    address target,
    bytes calldata callData,
    uint256 nativeValue
) internal view returns (bytes32) {
    // Include nonce and chain ID as additional components
    bytes32 proposalHash = keccak256(
        abi.encodePacked(target, callData, nativeValue, nonce, chainId)
    );
    return proposalHash;
}

Increment Nonce for Each New Proposal.

## Tools Used
VSC

## Recommended Mitigation Steps
To mitigate the vulnerability caused by breaking the uniqueness invariant when generating proposal hashes, the following steps should be taken:

Update the proposal hash computation: Modify the _processCommand function to include the nonce and chain ID as additional components when generating the proposal hash.

Retrieve the nonce and chain ID from helper functions within the contract, and use them as the fourth and fifth components, respectively, in the Keccak256 hash calculation.

By implementing the nonce and chain ID components, replay attacks will be prevented, ensuring the uniqueness of each proposal and enhancing the overall security of the governance system.


## Assessed type

Governance
Proposal cannot be executed if signers update their accounts and threshold halfway
Audit: 2023-07-axelar-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact

If signers update their accounts and threshold halfway into voting, then the proposal cannot be executed anymore

## Proof of Concept

execute is protected under onlySigners()

```
    function execute(
        address target,
        bytes calldata callData,
        uint256 nativeValue
->    ) external payable onlySigners {
        _call(target, callData, nativeValue);
    }
```

onlySigners uses signerEpoch for the voting, and signerEpoch is updated when _rotateSigners() is called

```
    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.
```
```
     */
    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 InvalidSigners();


        if (newThreshold == 0) revert InvalidSignerThreshold();


->        ++signerEpoch;
```

If rotateSigners() is called inbetween votes, then signerEpoch will be updated. If the signers decides to update the newAccounts and newThreshold for signers before a certain proposal is executed, then the proposal will never be able to execute anymore because `Voting storage voting = votingPerTopic[signerEpoch][topic]` will have a different signerEpoch.

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

## Tools Used

Manual Review

## Recommended Mitigation Steps

Make sure that all proposals are executed first before signers are allowed to update their signer threshold and signer accounts.


## Assessed type

Other
All co-signers pay during executeMultisigProposal
Audit: 2023-07-axelar-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/governance/AxelarServiceGovernance.sol#L48-L52
https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/auth/MultisigBase.sol#L59-L62


# Vulnerability details

## Impact
The [executeMultisigProposal](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/governance/AxelarServiceGovernance.sol#L48-L52) will receive payment from all cosigners when only one payment of nativeValue amount is required.

## Proof of Concept
The [executeMultisigProposal](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/governance/AxelarServiceGovernance.sol#L48-L52) requires native payment and therefore requires the caller to pay an amount equivalent to nativeValue. The onlySigners however, will only allow the executeMultisigProposal function body [to execute for the caller that reaches the votes threshold](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/cgp/auth/MultisigBase.sol#L59-L62).


From AxelarServiceGovernance.sol
```solidity
    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();

        multisigApprovals[proposalHash] = false;

        _call(target, callData, nativeValue);

        emit MultisigExecuted(proposalHash, target, callData, nativeValue);
    }
```

From MultisigBase.sol
```solidity
    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;
        }

        // 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);

        _;
    }
```

## Tools Used
n/a

## Recommended Mitigation Steps
Either refund the native amount sent until there are insufficient votes to pass the proposal, or partially refund in amount eq
Addresses in modifier not set correctly 
Audit: 2023-07-axelar-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
Detailed description of the impact of this finding.
Addresses that are mintlimiter but not governance will revert thus being able not to call some functions as intended. 

## Proof of Concept
In the comment it was stated that it is either mint limiter or governance but the code executes "and"
  /*
     * @dev Reverts with an error if the sender is not the mint limiter or governance.
     */
    modifier onlyMintLimiter() {
        if (msg.sender != getAddress(KEY_MINT_LIMITER) && msg.sender != getAddress(KEY_GOVERNANCE)) revert NotMintLimiter();

        _;
    }
This will affect those function that carry the  onlyMintLimiter function being basically only  accessible only the governance address only, since its not accessible to mint limiter addresses that are not governance addresses
## Tools Used
Manual review 
## Recommended Mitigation Steps
Change the "and" operator to "OR"


## Assessed type

DoS
Interchain token transfer can be Dossed Due To Flow Limit
Audit: 2023-07-axelar-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/its/token-manager/TokenManager.sol#L83-L173
https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/its/interchain-token/InterchainToken.sol#L1-L106


# Vulnerability details

## Impact
A large token holder can send back and forth tokens, using the flow limit to the capacity in start of every epoch making the system unusable for everyone else.

## Proof of Concept
Interchain tokens can be transferred from one chain to another via the token manager and interchain token service.

And there is a limit imposed, for both the flow out and flow in.

Flow out happens when we send the token from one chain to another. Lets say arbitrum to optimism and we are sending USDC. So in this case, in context of arbitrum it will be flow out and in context of optimism it will be flow in and and receiver on optimism will get the tokens via the token manager 'giveToken()' callable by the inter chain token service.

But there is a flow limit impose per epoch. 

One Epoch = 6 hours long.

So there cannot be more than certain amount of tokens sent between the chain per 6 hours. This is done to protect from the uncertain conditions like a security breach and to secure as much of tokens as possible.

But the problem with such design is big token holder or whale could easily exploit it to DOS the other users.


Consider the following scenerio:

1. Epoch starts.
2. Limit imposed for the flow is 10 million USDC (considering usdc to be interchain token for ease of understanding).
3. A big whale transfer 10 million USDC in start of the epoch and those are there and may or may not receive them on other end right away.
4. But the limit have been reached for the specific epoch. Now no other user can use the axelar interchain token service to transfer that particular token on the Dossed lane.
5. Now attacker can repeat the process across multiple lanes on multiple chain or one, in start of every epoch making it unusable for every one with very minimum cost.


This attack is pretty simple and easy to acheive and also very cheap to do, specifically on the L2's or other cheap chains due to low gas price.

Function using the flow limit utility in `tokenManager.sol` are following

```solidity
    function sendToken(
        string calldata destinationChain,
        bytes calldata destinationAddress,
        uint256 amount,
        bytes calldata metadata
    ) external payable virtual {
        address sender = msg.sender;
        amount = _takeToken(sender, amount);
        _addFlowOut(amount);
        interchainTokenService.transmitSendToken{ value: msg.value }(
            _getTokenId(),
            sender,
            destinationChain,
            destinationAddress,
            amount,
            metadata
        );
    }

    /**
     * @notice Calls the service to initiate the a cross-chain transfer with data after taki
Permits may be reused after token upgrade
Audit: 2023-07-axelar-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/its/token-implementations/StandardizedToken.sol#L19
https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/its/token-implementations/ERC20Permit.sol#L44-L48


# Vulnerability details

## Impact
The StandardizedToken contract inherits the ERC20Permit contract which in the case of an upgradable/proxied Token would allow permits for a previous version of the Token to be used on any subsequent version of it.

NOTE that ERC20Permit is not explicitly in scope but used/inherited by StandardizedToken which is in scope.

## Proof of Concept
The [ERC20Permit @ line 44-48](https://github.com/code-423n4/2023-07-axelar/blob/2f9b234bb8222d5fbe934beafede56bfb4522641/contracts/its/token-implementations/ERC20Permit.sol#L44-L48) defines the domain separator as follows
```solidity
    function _setDomainTypeSignatureHash(string memory name) internal {
        DOMAIN_SEPARATOR = keccak256(
            abi.encode(DOMAIN_TYPE_SIGNATURE_HASH, keccak256(bytes(name)), keccak256(bytes('1')), block.chainid, address(this))
        );
    }
```

Since the above code would be called by a proxy `address(this)` will never change, and given that the version is fixed to bytes('1'), permits issued before a token implementation upgrade would still be valid after the upgrade.

## Tools Used
n/a

## Recommended Mitigation Steps
Allow version to be increased between upgrades to ensure a distinct DOMAIN_SEPARATOR at each upgrade.


## Assessed type

Access Control
Users do not get charged for the value their proposal will need
Audit: 2023-07-axelar-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/interchain-governance-executor/InterchainProposalSender.sol#L59
https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/interchain-governance-executor/InterchainProposalSender.sol#L80
https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/interchain-governance-executor/InterchainProposalSender.sol#L88


# Vulnerability details

## Impact
Depending on whether the destination chain InterchainProposalExecutor's native token balance the transaction will either steal funds or will fail.

## Proof of Concept
Users can provide an amount of native tokens they want to send to the call they will make on the destination chain. The issue arises because the InterchainProposalSender contract only checks for whether an appropriate amount of tokens has been sent to cover gas, and not for the value passed in the call.
This will either cause funds that are present in the executor contract to inappropriately get sent somewhere else or will cause the transaction to silently fail because the executor will not have any native tokens in its balance to work with.

## Tools Used
Manual review

## Recommended Mitigation Steps
Consider implementing a system that makes users send native tokens along with the native tokens for gas.
Keep in mind that this may open up other vectors because of the discrepancy of native token prices on different chains.


## Assessed type

Other
InterchainProposalExecutor doesn't support actions with value
Audit: 2023-07-axelar-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
An interchain call consists of the target address, calldata, and value. When InterchainProposalExecutor performs the call, it passes the value along
```solidity
    function _executeProposal(InterchainCalls.Call[] memory calls) internal {
        for (uint256 i = 0; i < calls.length; i++) {
            InterchainCalls.Call memory call = calls[i];
            (bool success, bytes memory result) = call.target.call{ value: call.value }(call.callData);
```

This call will fail for non-zero value because this code path is not payable. In fact, there are no payable or receive methods neither in InterchainProposalExecutor, nor in any of its parent contracts. 
The only way this may not fail is if someone force feeds the contract via selfdestruct. It is safe to assume this is not the intended way to use the contract.

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

## Tools Used
Manual

## Recommended Mitigation Steps
I think the best option is to implement it similar to how InterchainGovernance work. After the message is approved by AxelarGateway, save it in storage and allow anyone to execute it in a separate call, while attaching the value along.

Another option would be to add a `receive` method so that the executor's balance can be refilled before executing an action.


## Assessed type

call/delegatecall
The is no way for native tokens to get sent to InterchainProposalExecutor
Audit: 2023-07-axelar-findings
Severity: MEDIUM

# Lines of code

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


# Vulnerability details

## Impact
Proposals that require value cannot be executed as native tokens on the other side of the bridge cannot be provided.

## Proof of Concept
Proposals have a value parameter, which allows users to specify what amount of native tokens should be passed when calling the destination contract. The issue arises because there is no way for native tokens to be sent to the InterchainProposalExecutor contract so it can properly execute the proposal.

## Tools Used
Manual Review

## Recommended Mitigation Steps
Add a receive function to InterchainProposalExecutor or AxelarExecutable so native tokens can be sent to the destination chain executor contract.


## Assessed type

Other
MID-Risk Vulnerabilities in the Axelar Smart Contracts
Audit: 2023-07-axelar-findings
Severity: MEDIUM

# Lines of code

s://github.com/code-423n4/2023-07-axelar/tree/main/contracts/cgp/governance/AxelarServiceGovernance.sol#L73


# Vulnerability details

## Impact

The vulnerabilities that I have identified could have a significant impact on the Axelar network. These vulnerabilities could be exploited by an attacker to:

Gain control of the Axelar network by proposing and voting on malicious proposals.
Mint or burn tokens in an unauthorized manner, which could have a significant impact on the value of the token.
Replace the TokenManager contract with a malicious contract, which would allow them to mint or burn tokens in an unauthorized manner.
## Proof of Concept

The proof of concept for each vulnerability is as follows:

AxelarServiceGovernance.sol
The contract does not have any checks to prevent an attacker from proposing a malicious proposal. This can be demonstrated by proposing a malicious proposal that would give the attacker control of the Axelar network.
The contract does not have any checks to prevent an attacker from voting on a malicious proposal. This can be demonstrated by voting on a malicious proposal that would give the attacker control of the Axelar network.
MultisigBase.sol
The contract does not have any checks to prevent an attacker from adding malicious signers to the multisig. This can be demonstrated by adding a malicious signer to the multisig, giving the attacker control of the multisig.
The contract does not have any checks to prevent an attacker from removing authorized signers from the multisig. This can be demonstrated by removing an authorized signer from the multisig, giving the attacker control of the multisig.
Multisig.sol
The contract does not have any checks to prevent an attacker from submitting a transaction with invalid signatures. This can be demonstrated by submitting a transaction with invalid signatures, which would be approved by the multisig.
InterchainToken.sol
The contract does not have any checks to prevent an attacker from minting or burning tokens in an unauthorized manner. This can be demonstrated by minting or burning tokens in an unauthorized manner, which could have a significant impact on the value of the token.
TokenManagerProxy.sol
The contract does not have any checks to prevent an attacker from replacing the TokenManager contract with a malicious contract. This can be demonstrated by replacing the TokenManager contract with a malicious contract, which would allow the attacker to mint or burn tokens in an unauthorized manner.
## Tools Used

The tools that I used to identify these vulnerabilities include:

Solidity
Remix IDE
Etherscan
## Recommended Mitigation Steps

The following mitigation steps can be taken to address the vulnerabilities that I have identified:

Add checks to the contracts to prevent attackers from proposing malicious proposals, voting on malicious proposals, adding malicious signers to the multisig, removing authorized signers from the multisig, submitting transactions wi
bypass flow limit by transferring tokens at epoch's boarder
Audit: 2023-07-axelar-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/its/utils/FlowLimit.sol#L114
https://github.com/code-423n4/2023-07-axelar/blob/main/contracts/its/utils/FlowLimit.sol#L127


# Vulnerability details

## Impact
Token flow can reach 2*flow_limit in a very short time.

## Proof of Concept
We store the flow out and flow in tokens numbers for every epoch:

```solidity
    /**
     * @dev Returns the slot which is used to get the flow out amount for a specific epoch
     * @param epoch The epoch to get the flow out amount for
     * @return slot The slot to get the flow out amount from
     */
    function _getFlowOutSlot(uint256 epoch) internal pure returns (uint256 slot) {
        slot = uint256(keccak256(abi.encode(PREFIX_FLOW_OUT_AMOUNT, epoch)));
    }

    /**
     * @dev Returns the slot which is used to get the flow in amount for a specific epoch
     * @param epoch The epoch to get the flow in amount for
     * @return slot The slot to get the flow in amount from
     */
    function _getFlowInSlot(uint256 epoch) internal pure returns (uint256 slot) {
        slot = uint256(keccak256(abi.encode(PREFIX_FLOW_IN_AMOUNT, epoch)));
    }


        uint256 epoch = block.timestamp / EPOCH_TIME;
        uint256 slotToAdd = _getFlowInSlot(epoch);
        uint256 slotToCompare = _getFlowOutSlot(epoch);
        _addFlow(flowLimit, slotToAdd, slotToCompare, flowInAmount);
```

So for every new epoch, the flow out/in number will be zero, so an attacker can:
1. At epoch1_start + EPOCH_TIME - 1, trigger a token flow reaching the limit.
2. At epoch1_start + EPOCH_TIME, the flow out/in number stored is zeroed.
3. At epoch1_start + EPOCH_TIME, trigger another toke flow reaching the limit.

Attackers can use this method to gain financial gain, etc.


## Tools Used
Manual Review.

## Recommended Mitigation Steps
Add a limit for every transfer, thus making the attack more expensive.



## Assessed type

Context