xanoutas/solidity-security-findings huggingface dataset:
Unsafe message encode and decode for cross chain message transfer and in execution process through axelar 
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/PoolManager.sol#L78
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/gateway/Gateway.sol#L98
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/gateway/routers/axelar/Router.sol#L24
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/gateway/Messages.sol#L8


# Vulnerability details

## Impact
The cross chain message passing is done through the axelar gateway contracts.

To pass the message, the message has to be formatted (abi.encode) and sent to destination chain from source chain. In destination chain, through gateway contract, the received message is decoded and then respective functions are executed.

The issue is, the method which is used to encode and decode the message is inconsistent with what is recommended in Axelar documentation.

Due to this, the message can not be properly relayed which causes in the disruption in cross chain contract calls.

## Proof of Concept

Lets take one example where cross chain communication is initiated and propagated till the execution on the destination chain.

The call flow like this, ```PoolManager,, InvestmentManager -> Gateway(source chain) -> Messages-> Router ->  Gateway( destination chain for execution)```

The call is coming from Gateway.

(https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L234)

```solidity
    function handleExecutedCollectInvest(
        uint64 poolId,
        bytes16 trancheId,
        address recipient,
        uint128 currency,
        uint128 currencyPayout,
        uint128 trancheTokensPayout
    ) public onlyGateway {
```

https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/gateway/Gateway.sol#L329

```solidity
        } else if (Messages.isExecutedCollectInvest(message)) {
            (
                uint64 poolId,
                bytes16 trancheId,
                address investor,
                uint128 currency,
                uint128 currencyPayout,
                uint128 trancheTokensPayout
            ) = Messages.parseExecutedCollectInvest(message);
            investmentManager.handleExecutedCollectInvest(
                poolId, trancheId, investor, currency, currencyPayout, trancheTokensPayout
            );
```

when we look at the message encoding process.

https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/gateway/Gateway.sol#L252-L258

```solidity
    function collectInvest(uint64 poolId, bytes16 trancheId, address investor, uint128 currency)
        public
        onlyInvestmentManager
        pauseable
    {
        outgoingRouter.send(Messages.formatCollectInvest(poolId, trancheId, _addressToBytes32(investor), currency));
    }
``
Rouge ward can remove auth permission from other wards and then remove themselves
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/util/Auth.sol#L14


# Vulnerability details

In a protocol, the deny function is used to remove the ward permissions from an address. This is actually a serious thing to consider that can actually occur, if a ward contract or account is obtained and other wards are not aware, the rogue ward can actually remove the wards before they actually have a chance to pause the contract to stop the ward. Here's a potential security scenario:

An attacker, Ben, either through compromising a private key or social engineering, becomes one of the protocol's wards

With ward privileges, Ben decides to use the deny function to remove every other ward in the protocol systematically.

As Ben removes all other wards, the protocol's governance becomes centralized around him. This means that Alice has full control over critical decisions

Ben can go even further by using his centralized power to enact decisions that disrupt the protocol's intended functioning. This can lead to financial losses for users and damage to the protocol's reputation.

After causing disruption, Ben can choose to remove himself as a ward using the same deny function. This effectively leaves the protocol without any governance mechanism or ward, rendering it useless

With no administrators or wards left, the project is effectively frozen and cannot be resumed or managed.
Users may lose access to their funds or be unable to transact within the project.
This example illustrates how an attacker with control over a contract that has permission management capabilities can potentially exploit vulnerabilities and disrupt a decentralized system. 

## Proof of Concept
```
 /// @notice removes the ward permissions from an address on a contract
    /// @param target the address of the contract
    /// @param user the address which persmissions should be removed
    function denyContract(address target, address user) public auth {
        AuthLike(target).deny(user);
        emit DenyContract(target, user);
    }

// @dev Remove permissions from the user
    function deny(address user) external auth {
        wards[user] = 0;
        emit Deny(user);
    }
```
as you can see, a rouge contract can carry out this attack with no problems, at a targeted time oblivious to other wards before the protocol can be paused

## Recommended Mitigation Steps

The same way there's a executeRely, there also should a TIme lock executeDeny, to give time to all wards in the protocol the time and appropriate time to respond and perform the necessary security actions to stop the rouge ward.


## Assessed type

Access Control
LiquidityPool inflation attack
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L325
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L117


# Vulnerability details

## Bug Description

The `LiquidityPool` uses an algorithm that converts prices to shares through a linear relationship. For instance, if there are 10,000 assets and 100 shares, then holding 100 assets should yield 1 share.
However, a situation arises when investor sends only 99 assets. In such cases, the conversion rounds down to zero, resulting in zero shares.

It's important to note that no one would intentionally make such a financial loss. Nevertheless, a potential threat arises when an attacker can frontrun a `LiquidityPool.requestDeposit`.

## Proof-of-Concept

A test scenario illustrating changes in the assets-to-shares ratio:

Upon witnessing an investor initiate a `LiquidityPool .requestDeposit` with a 99 currency amount, an attacker frontruns the transaction with a higher gas price, submitting a 10,000 currency amount request. In this case, the investor who was frontrun will receive zero TrancheTokens.

```solidity
function test_InflationAttack() public {
        uint8 TRANCHE_TOKEN_DECIMALS = 18;
        uint8 INVESTMENT_CURRENCY_DECIMALS = 18;
        bytes16 trancheId = "0x333";
        uint128 currencyId = 1;
        uint64 poolId = 1;
        ERC20 currency = _newErc20(
            "Currency",
            "CR",
            INVESTMENT_CURRENCY_DECIMALS
        );
        address lPool_ = deployLiquidityPool(
            poolId,
            TRANCHE_TOKEN_DECIMALS,
            "",
            "",
            trancheId,
            currencyId,
            address(currency)
        );
        LiquidityPool lPool = LiquidityPool(lPool_);
        homePools.updateTrancheTokenPrice(poolId, trancheId, currencyId, 1e20);
        // invest
        uint256 investmentAmount = 10000;
        homePools.updateMember(poolId, trancheId, self, type(uint64).max);
        currency.approve(address(investmentManager), investmentAmount);
        currency.mint(self, investmentAmount);
				//frontrun
        lPool.requestDeposit(investmentAmount, self);
        uint128 _currencyId = poolManager.currencyAddressToId(
            address(currency)
        ); // retrieve currencyId
        uint128 currencyPayout = 10000;
        uint128 firstTrancheTokenPayout = 100;
        homePools.isExecutedCollectInvest(
            poolId,
            trancheId,
            bytes32(bytes20(self)),
            _currencyId,
            currencyPayout,
            firstTrancheTokenPayout
        );
        // assert deposit & mint values adjusted
        assertEq(lPool.maxDeposit(self), currencyPayout);
        assertEq(lPool.maxMint(self), firstTrancheTokenPayout);

        // second user will get 0 shares for 99 assets
        uint256 convertedShares = lPool.convertToShares(99);
New Ward Can Revoke Admin Access
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/Root.sol#L95-L101


# Vulnerability details

## Impact
A Newly added ward can remove all the wards from the system, including the admin one.

## Proof of Concept
There is not a mechanism to prevent newly added wards from removing everyone else access' to the contracts, including the admin.

## Tools Used
Manual

## Recommended Mitigation Steps
add some sort of hierarchy, like adding a main [multisig/dao] wallet that governs above all the other wards. Implementing AccessControl [Openzeppelin] roles would also be a good way to prevent this.


## Assessed type

Access Control
An attacker can drain all the tokens from ``UserEscrow`` contract.
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/LiquidityPool.sol#L247-L255


# Vulnerability details

## Impact
An user who is allowed to invest can maliciously drain all the tokens from the ``UserEscrow`` contract from ``decreaseDepositRequest()`` and ``decreaseRedeemRequest()`` of ``LiquidityPool.sol`` contract. Both functions are first send to the router and when the call is returned by the router ``handleExecutedDecreaseInvestOrder()`` and ``handleExecutedDecreaseRedeemorder()`` are executed which both lack necessary checks to verify whether the user has requested deposit/redeem or not. The amount returned by this function to the user is also not verified with the amount send by the user while requesting deposit/redeem.

## Proof of Concept
1. Alice requests a deposit of X amount of currency tokens and those tokens are sent to to the ``UserEscrow`` contract from the ``requestDeposit`` function.
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L136
2. Eve sees this transaction and calls ``decreaseDepositRequest()`` on ``LiquidityPool.sol`` contract to  decrease her deposit of same currency by X amount.
3. Eve steals all the X amount of Alice's currency.

This same attack is also prevalent with ``decreaseRedeemRequest()`` function.

## Tools Used
Manual Analysis

## Recommended Mitigation Steps
In the ``handleExecutedDecreaseInvestOrder()`` and ``handleExecutedDecreaseRedeemorder()``, add the mechanism to do the following things:
1. There is no check to determine whether the user who is requesting decrease deposit/redeem order has deposited previously. This can be tracked using a mapping and should revert user has not deposited.
2. There is no check to verify the amount asked to be decreased is less than or equal to the amount deposited by the user. This should also be tracked and checked.





## Assessed type

Other
"Divide-by-Zero Risk in `convertToShares` Function"
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L329-L332


# Vulnerability details

## Description
The `convertToShares` function calculates the number of shares based on the provided assets and the "latestPrice" obtained from the liquidityPool. While the code may appear straightforward, there is a specific security concern related to divide-by-zero errors in this function.

## Impact
> Divide-by-Zero Risk-> The latestPrice value obtained from the liquidityPool is used as the denominator in a division operation. If, at any point, this latestPrice value becomes zero, it can result in a divide-by-zero error. Such an error would cause the contract to halt, potentially leading to unexpected behavior and disrupting normal operations

## Tools Used
Manual Review

## Recommended Mitigation Steps
Divide-by-Zero Protection: Before executing the division operation, implement a validation check to ensure that the latestPrice value is non-zero. Utilize a require statement to validate this condition before proceeding with share calculations, as shown below-

```
uint256 latestPrice = LiquidityPoolLike(liquidityPool).latestPrice();
require(latestPrice != 0, "Latest price is zero.");
shares = assets.mulDiv(10 ** (PRICE_DECIMALS + trancheTokenDecimals - currencyDecimals), latestPrice, MathLib.Rounding.Down);
```


## Assessed type

Math
users can mint TT tokens without locking/depositing any currency tokens
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/LiquidityPool.sol#L214-L217
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/gateway/routers/axelar/Router.sol#L73-L86
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/LiquidityPool.sol#L214-L216
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/gateway/Gateway.sol#L200-L210
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/gateway/routers/axelar/Router.sol#L73-L86
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/gateway/Gateway.sol#L329-L340
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L248-L249
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L174-L185
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L277-L292
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/LiquidityPool.sol#L141-L144
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L427-L441
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L551-L558
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L569-L582
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L467-L479


# Vulnerability details

## Impact

When users seek to invest in a Centrifuge pool using liquidity pools, the initial step involves calling the `requestDepositOrder` function to send a deposit request to the Centrifuge chain. During this process, necessary state variables such as max `deposit/mint` values are updated. Subsequently, the Centrifuge chain responds with data that is stored within the `investManager.sol` contract. This data remains associated with the epoch in which the request was initiated and becomes executable in the upcoming epoch. However, users have the ability to reduce their deposit orders by calling the `decreaseDepositRequest`, reclaim their currencies, and subsequently call the `deposit` function to mint TT tokens without requiring any currency. more details in POC.

## Proof of Concept

Let's consider a hypothetical scenario in which the currency is DAI, and the Tranche token to be minted is TT. Alice intends to deposit/invest 10,000 USDC at a rate of 1.25 DAI per USDC, resulting in her receiving 8,000 TT.

1-Alice's first action is to call the `requestDepositOrder` function, which sends an deposit or
`approve` function can be frontrun and funds will be stolen as a result
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/token/ERC20.sol#L131-L137
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/token/ERC20.sol#L106-L129


# Vulnerability details

## Impact
The user that gives allowances will lose funds.

## Proof of Concept
In the file `ERC20.sol` there is a function `approve`. This function is problematic as it is susceptible to frontrunning attacks.

PoC:
Consider the following scenario: Alice calls the function `approve` (with Bob's address and `value == 20`) and approves Bob to spend 20 units of a token on her behalf. Shortly after that Alice decides to decrease Bob's allowance to 10 units of a token by calling again the function `approve` (with Bob's address and `value == 10`). At the end, Alice expects that Bob will be able to spend 10 units of a token on her behalf. Bob carefully monitors the mempool and sees Alice's two transactions - the one that sets Bob's allowance to 20 and the one that sets Bob's allowance to 10. Bob waits the first transaction to be executed and the state to be updated. After the first transaction is completed, Bob is allowed to use 20 units of a token on Alice's behalf. Bob frontruns the second Alice's transaction calling the function `transferFrom` (from the file `ERC20.sol`) and sending the 20 units to his address. The second Alice's transaction is executed after that and Bob is granted to use 10 more units of a token on Alice's behalf. Bob calls the `transferFrom` function again and transfers 10 more units of a token to his address. As a result Bob managed to take 30 units of a token from Alice, while Alice expects that Bob can control only 10 units of her tokens. Thus, Bob manages to steal 20 units of a token from Alice.

## Tools Used
Manual review

## Recommended Mitigation Steps
Remove the `approve` function and leave only the functions `increaseAllowance` and `decreaseAllowance`.


## Assessed type

MEV
Blocking `assets`/`shares` in `escrow`
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L117-L141
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L148-L172


# Vulnerability details

## Impact
An investor can lose a part of `assets` or `shares` due to their blocking in `escrow`.

## Proof of Concept
Suppose the user decided to invest an amount of assets which is more than `type(uint128).max`. This can be done by calling the [`requestDeposit`](https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/LiquidityPool.sol#L214-L217) function several times.
The flow goes to the [`InvestmentManager.requestDeposit`](https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L117-L141) function which casts `uint256` to `uint128` with revert in case of `currencyAmount > type(uint128).max`, but amounts in each transaction will be less but the total amount can be more.
```solidity
151        uint128 _currencyAmount = _toUint128(currencyAmount);
```
So all amounts can be accumulated in the `escrow` contract and all messages `increaseInvestOrder` can be sent to the `gateway`.
```solidity
136        SafeTransferLib.safeTransferFrom(currency, user, address(escrow), _currencyAmount);
137
138        gateway.increaseInvestOrder(
139            lPool.poolId(), lPool.trancheId(), user, poolManager.currencyAddressToId(lPool.asset()), _currencyAmount
140        );
```
Then the user changed his mind and sent `_currencyAmount == 0` to cancel the order.
```solidity
127        if (_currencyAmount == 0) {
128            // Case: outstanding investment orders only needed to be cancelled
129            gateway.cancelInvestOrder(
130                lPool.poolId(), lPool.trancheId(), user, poolManager.currencyAddressToId(lPool.asset())
131            );
132            return;
133        }
```
This call should be executed with the total amount of sended assets but the [`handleExecutedDecreaseInvestOrder`](https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L277-L292) can receive only `type(uint128).max`.
```solidity
277    function handleExecutedDecreaseInvestOrder(
278        uint64 poolId,
279        bytes16 trancheId,
280        address user,
281        uint128 currency,
282        uint128 currencyPayout
283    ) public onlyGateway {
```
So the user receives back `type(uint128).max` and the rest of the request remains in the `escrow`.
```solidity
291        SafeTransferLib.safeTransferFrom(_currency, address(escrow), user, currencyPayout);
```
Absolutely the same thing with the redeem request flow: [`requestRedeem`](https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L148-L172) and [`handleExecutedDecreaseRedeemOrder`]