xanoutas/solidity-security-findings huggingface dataset:
Any user can drain the escrow contract by calling `decreaseDepositRequest` with more amount than they deposited into the escrow while requesting.
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact

In the protocol, users submit deposit requests to the Centrifuge gateway for depositing assets into the Liquidity Pools. There is also a mechanism to decrease this deposit order by calling [LiquidityPool::decreaseDepositRequest()](https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L174-L185) which decreases their deposit request and sends it back to the user from the escrow contract.

But there is no check to ensure that amount passed to the `decreaseDepositRequest()` function is greater than the amount deposited by the user (held by the escrow contract until request is approved).


This can enable a malicious user to submit a `deposit` request and immediately call `decreaseDepositRequest` with amounts greater than their deposit to drain the escrow contract.

## Proof of Concept

There is no check to see if the `currencyAmount` exceeds balance of user.

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

```solidity
//File::src/InvestmentManager.sol

 function decreaseDepositRequest(uint256 _currencyAmount, address user) public auth {
        uint128 currencyAmount = _toUint128(_currencyAmount);
        LiquidityPoolLike liquidityPool = LiquidityPoolLike(msg.sender);
        require(liquidityPool.checkTransferRestriction(address(0), user, 0), "InvestmentManager/not-a-member");
        gateway.decreaseInvestOrder(
            liquidityPool.poolId(),
            liquidityPool.trancheId(),
            user,
            poolManager.currencyAddressToId(liquidityPool.asset()),
            currencyAmount
        );
    }
```

Attack scenario is as follows:
1. User- Bob sends request to Deposit while escrowing 100 tokens(for eg, usdc)
2. Alice also sends DepositRequest for 100 usdc .
3. The escrow contract now holds 200 usdc.
4. Alice can call `decreaseDepositRequest` with 200 usdc and since there are no checks, the escrow contract will transfer 200 usdc to Alice.
5. Now Alice has more tokens than what she started with and drained the escrow contract.

A PoC for depicting this attack scenario is given as follows. It uses a slightly modified version of `testDecreaseDepositRequest` from test/LiquidityPool.t.sol so this test can be run by just pasting into the same file.

```solidity

function testDecreaseDepositRequestMine(
        uint64 poolId,
        uint8 decimals,
        string memory tokenName,
        string memory tokenSymbol,
        bytes16 trancheId,
        uint128 price,
        uint128 currencyId,
        uint256 amount,
        uint64 validUntil
    ) public {
        vm.assume(cur
Users may not redeem the their tranche tokens and suffer loss.
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/6e735d42c1e0cfe52bbbd74f0e8b0c3541073060/src/InvestmentManager.sol#L167
https://github.com/code-423n4/2023-09-centrifuge/blob/6e735d42c1e0cfe52bbbd74f0e8b0c3541073060/src/InvestmentManager.sol#L272
https://github.com/code-423n4/2023-09-centrifuge/blob/6e735d42c1e0cfe52bbbd74f0e8b0c3541073060/src/InvestmentManager.sol#L273


# Vulnerability details

## Impact

In case of the stablecoin depegging, users may may not redeem the their tranche tokens and suffer loss.

## Proof of Concept

A tranche allows multiple stablecoins to be the currencies that users can deposit to get the tranche tokens. An example would be a tranche that allows users to deposit USDT and USDC. One feature of the tranche is that users can redeem whatever currency that they like, as long as they have the trance tokens.

        lPool.transferFrom(user, address(escrow), _trancheTokenAmount);

https://github.com/code-423n4/2023-09-centrifuge/blob/6e735d42c1e0cfe52bbbd74f0e8b0c3541073060/src/InvestmentManager.sol#L167

A user can deposit USDT to get the tranche tokens. Later he can go to the USDC liquidity pool to redeem his tranche tokens to get USDC.

        function requestRedeem(uint256 shares, address owner) public withApproval(owner) {
            investmentManager.requestRedeem(shares, owner);
            emit RedeemRequested(owner, shares);
        }

The USDC is then moved from the `escrow` to `userEscrow` and then to the user when he `processRedeem`.

        userEscrow.transferIn(_currency, address(escrow), recipient, currencyPayout);

https://github.com/code-423n4/2023-09-centrifuge/blob/6e735d42c1e0cfe52bbbd74f0e8b0c3541073060/src/InvestmentManager.sol#L272

The problem is that the amount of USDC is limited by the amount of USDC that users have deposited.

Imagine a scenario when USDT is depegged. All investors who deposited USDT will go to redeem the USDC. It leads to the investor who deposited USDC not being able to redeem their USDC because everyone is front-run each other to get the fixed amount of USDC. Investors will have their redeem process revert because of USDC lacking in the `escrow`. It is even worse when their trance tokens are already burnt in the redeem process. It leads to losses for the investors.

        LiquidityPoolLike(liquidityPool).burn(address(escrow), trancheTokensPayout);

https://github.com/code-423n4/2023-09-centrifuge/blob/6e735d42c1e0cfe52bbbd74f0e8b0c3541073060/src/InvestmentManager.sol#L273

Another option if the investor who deposited USDC cannot afford to front-run the USDT depositers, he may go to the USDT liquidity pool to redeem the depegged USDT and also suffer loss.

## Tools Used

Manual

## Recommended Mitigation Steps

- Check balance of escrow before allowing `requestRedeem` so that the redeem process will not be reverted.
- Consider having a feature that switches so that only allow redeem the currency that the user has deposited.


## Assessed type

Other
Relying on string comparisons to determine which parameter to update in the file() function is brittle and could lead to unintended consequences.
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/PoolManager.sol#L120-L125


# Vulnerability details

## Impact
This can allow unintentionally changing sensitive state variables

## Proof of Concept
The vulnerability arises because:

file() relies on a simple string comparison of the what parameter to determine which state variable to update.
A developer could accidentally type "investmenManager" instead of "investmentManager".
This would pass the string comparison check and update an unintended state variable.
Proof of concept:
- Developer wants to update investmentManager
- Developer calls file("investmenManager", badActor)
- String comparison passes because "investmenManager" == "investmenManager"
gateway variable is updated to badActor unexpectedly

## Tools Used
Manual
## Recommended Mitigation Steps
use an enum instead of a string to prevent typos


## Assessed type

Other
InvestmentManager.requestDeposit Arbitrary send erc20
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/InvestmentManager.sol#L117-L141
https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/InvestmentManager.sol#L136


# Vulnerability details

## Impact
InvestmentManager.requestDeposit. In this function, the SafeTransferLib.safeTransferFrom function is called with an arbitrary from address. This means that the attacker can control who the tokens are transferred from.

## Proof of Concept
https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/InvestmentManager.sol#L136

## Tools Used
manual review

## Recommended Mitigation Steps
to fix this vulnerability is to use the msg.sender as the from address in the SafeTransferLib.safeTransferFrom function. This ensures that the tokens are always transferred from the account that is calling the function.
Here is the updated code:

function requestDeposit(uint256 currencyAmount, address user) public auth {
address liquidityPool = msg.sender;
LiquidityPoolLike lPool = LiquidityPoolLike(liquidityPool);
address currency = lPool.asset();
uint128 _currencyAmount = _toUint128(currencyAmount);

    // Check if liquidity pool currency is supported by the Centrifuge pool
    poolManager.isAllowedAsPoolCurrency(lPool.poolId(), currency);
    // Check if user is allowed to hold the restricted tranche tokens
    _isAllowedToInvest(lPool.poolId(), lPool.trancheId(), currency, user);
    if (_currencyAmount == 0) {
        // Case: outstanding investment orders only needed to be cancelled
        gateway.cancelInvestOrder(
            lPool.poolId(), lPool.trancheId(), user, poolManager.currencyAddressToId(lPool.asset())
        );
        return;
    }

    // Transfer the currency amount from user to escrow. (lock currency in escrow).
    SafeTransferLib.safeTransferFrom(msg.sender, user, address(escrow), _currencyAmount);

    gateway.increaseInvestOrder(
        lPool.poolId(), lPool.trancheId(), user, poolManager.currencyAddressToId(lPool.asset()), _currencyAmount
    );
}


## Assessed type

ERC20
https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/InvestmentManager.sol#L467-L480
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/InvestmentManager.sol#L474-L477


# Vulnerability details

## Impact
 In this function InvestmentManager._deposit, the require statement calls the lPool.transferFrom function with an arbitrary from address. This means that the attacker can control who the tokens are transferred from.

## Proof of Concept
https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/InvestmentManager.sol#L467-L480
https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/InvestmentManager.sol#L474-L477

## Tools Used
manuel review

## Recommended Mitigation Steps
to fix this vulnerability is to use the msg.sender as the from address in the require statement. This ensures that the tokens are always transferred from the account that is calling the function.
You can circumvent the security flaw in the InvestmentManager._deposit function by using SafeERC20.
The safeTransferFrom function ensures that the tokens are always transferred from the account that is calling the function.



## Assessed type

ERC20
Vulnerability: An Attacker can steal Tranche Tokens and Drain the Pool   / Contract: InvestmentManager.
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#L234-L253
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L277-L292


# Vulnerability details

## Impact
An Attacker can mint Tranche Tokens for free and use them to Drain the Pool and steal the user's money.

## Proof of Concept
Let's imagine that some users deposit money in the pool and mint tranches but they didn't redeem/withdraw their tokens, one of the users is an attacker that follow the next step to mint free tranche tokens and use them to steal the funds of the pool.

1.- First the attacker call **"requestDeposit(amount, user2)"** sending an amount of tokens to the escrow contract.

2.- After that the user call **"requestDeposit(0, user2)"** to cancel the order and get his money back.

3.- This will generate 2 calls to the centrifuge network: **"isExecutedCollectInvest and isExecutedDecreaseInvestOrder"** both will be executed after the epoch and return the flow to the system.

4.- The **"isExecutedCollectInvest"** will be executed and the tranche tokens will be minted for the user, but when this call is executed the system calls the function **"handleExecutedCollectInvest"** from the investment manager, this function only mints the tranche tokens for the user but doesn't take the tokens the user deposit as collateral from the escrow, leaving this tokens available for withdraw.

5.- Then the **"isExecutedDecreaseInvestOrder"** is executed this calls the function **"handleExecutedDecreaseInvestOrder"** in the investment manager and the tokens deposited in the escrow are returned to the attacker.

6.- Now the attacker can call the **"mint" function** in the liquidity pool and mint the tranche tokens to his wallet and he also got back his initial deposit, so he gets some tranche tokens for free.

7.- after that the attacker can call **"requestRedeem"** and then th **"withdraw"** function in the liquidity pool to withdraw some tokens in the pool and can repeat this attack until the pool is drained.

I created the following test in the LiquidityPool.t.sol file to validate the vulnerability:

This test shows that if an attacker sends the two calls in a row (to deposit and then cancel the deposit) he can hack the protocol and steal the tokens deposited for other users in the pool.

```
 function testDepositMintHack() public {
        uint128 currencyId = 1;
        uint256 amount = 1000 ether;
        uint64 validUntil = uint64(block.timestamp + 86400);
        uint128 price = 2 * 10 ** 27;
        bytes16 trancheId = "1";
        uint64 poolId = 1;
        /* string memory tokenSymbol = "ETHUSDT";
        string memory tokenName = "ETH"; */
        address attacker = address(1);

        address lPool_ = dep
Transactions could be frontrun to deposit assets and collect shares between the deposit request and collection
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/LiquidityPool.sol#L259-L262


# Vulnerability details

## Impact
Attacker can spoof deposit to get free shares.

## Proof of Concept
requestDeposit() - Requests a deposit, locks up the assets.

collectDeposit() - Collects the shares after deposit execution.

The vulnerability arises because:
requestDeposit() locks up the assets, but does not mint any shares.

There is a window between requestDeposit() and collectDeposit() where the deposit has not been executed yet.

An attacker could call requestDeposit(), then immediately call deposit() before collectDeposit() is called.
This would allow the attacker to collect shares, even though they didn't actually deposit any assets.
Proof of concept:
- Attacker requests deposit of 100 DAI using requestDeposit()
- 100 DAI is transferred from attacker to pool and locked
- Attacker immediately calls deposit(100 DAI)
- Attacker receives pool shares for 100 DAI deposit
- Attacker later calls collectDeposit() to get their 100 DAI back
- So the attacker has spoofed a deposit to get free shares.

## Tools Used
Manual

## Recommended Mitigation Steps
- Tracking deposits and only allowing shares to be collected if there is a corresponding request 
- Modifying collectDeposit() to check for a corresponding deposit request before minting shares
- Tracking deposits requested and collected per user, to prevent collecting shares without a deposit.



## Assessed type

Other
arbitrary sending erc20 
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/InvestmentManager.sol#L277-L292
https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/InvestmentManager.sol#L291


# Vulnerability details

## Impact
The InvestmentManager contract may be vulnerable to two security flaws. The transferFrom method is invoked with an arbitrary from address in InvestmentManager.requestRedeem. As a result, the attacker has control over who transfers the tokens. With an arbitrary from address, the SafeTransferLib.safeTransferFrom method is also invoked in the InvestmentManager.handleExecutedDecreaseInvestOrder function. As a result, the attacker has control over who transfers the tokens.

## Proof of Concept
https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/InvestmentManager.sol#L291

## Tools Used
manual review 

## Recommended Mitigation Steps
Use of the msg.sender as the from address in the transferFrom and SafeTransferLib.safeTransferFrom functions is advised to close these issues. This makes sure that the account invoking the function always transfers the tokens.


## Assessed type

ETH-Transfer
the pool could burn tokens without redeeming currency to artificially alter the price
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
It negatively impacts the deposit/redeem prices for users

## Proof of Concept
This is possible because _updateLiquidityPoolPrice relies on the payout amounts passed in to calculate the new price, but does not verify that a corresponding currency redemption happened
The vulnerable code is _updateLiquidityPoolPrice: https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L584-L589

An attacker could:
1. Mint some tokens normally, burning currency
2. Call _updateLiquidityPoolPrice with a fake trancheTokensPayout and 0 currency payout
3. This will lower the price since it appears a large redemption happened
4. Attacker can now deposit currency for cheap tokens


## Tools Used
Manual
## Recommended Mitigation Steps 
_updateLiquidityPoolPrice should check that totalSupply was reduced by trancheTokensPayout to ensure tokens were actually burned


## Assessed type

Other
Arbitrary from in transferFrom
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/InvestmentManager.sol#L148-L172
https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/InvestmentManager.sol#L167


# Vulnerability details

## Impact
In the function InvestmentManager.requestRedeem, the transferFrom function is called with an arbitrary from address. This means that the attacker can control who the tokens are transferred from.

## Proof of Concept
Your Solidity contract code has a flaw that lets an attacker decide who gets to handle the token transfers from in the InvestmentManager.requestRedeem method. This implies that the tokens could be taken from the victim's account by the attacker and used for bad. Using the msg.sender as the from address in the transferFrom method is the suggested solution for addressing this vulnerability. By doing this, it is guaranteed that the tokens are always transferred from the caller account.

https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/InvestmentManager.sol#L167

## Tools Used
manual review & slither 

## Recommended Mitigation Steps
The recommended way to fix this vulnerability is to use the msg.sender as the from address in the transferFrom function. This ensures that the tokens are always transferred from the account that is calling the function.


## Assessed type

ETH-Transfer
vulnerability in calculateDepositPrice because it does not validate that maxMint is greater than 0
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
This can block new deposits by setting the price to 0 when it should not be.

## Proof of Concept
It assumes that if maxMint is 0, there have been no deposits yet.
But an attacker could manipulate maxMint to be 0 even after deposits have occurred, by:
1. Calling requestDeposit and collectInvest to set maxMint > 0 initially
2. Calling cancelInvestOrder to set maxMint back to 0
Now calculateDepositPrice will incorrectly see maxMint as 0 and return a deposit price of 0, even though deposits have occurred.


## Tools Used
manual
## Recommended Mitigation Steps
explicitly validate that maxMint is greater than 0


## Assessed type

Other
The contract does not have a function to withdraw tokens that are sent to it
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/Escrow.sol#L6


# Vulnerability details

## Impact
The contract does not have a function to withdraw tokens that are sent to it. 
It can lead to permanent loss of funds if tokens are sent to the contract by mistake

## Proof of Concept
 An escrow contract typically holds funds or tokens until certain conditions are met, after which the funds are released. However, in this contract, there is no function defined that allows the withdrawal or release of the tokens once they are approved and stored in the contract. This means that once tokens are sent to this contract, they are effectively locked in with no way to retrieve them.

## Tools Used
Manual Review
## Recommended Mitigation Steps
To resolve this issue, you should add a withdrawal function to the contract. This function should allow the approved spender to withdraw the approved amount of tokens. Here is a simple example of how you could implement this:

```solidity
function withdraw(address token, uint256 amount) external auth {
    require(amount <= address(this).balance, "Insufficient balance in the contract");
    SafeTransferLib.safeTransfer(token, msg.sender, amount);
}
```

This function first checks if the contract has enough balance to fulfill the withdrawal request. If it does, it uses the `safeTransfer` function from the `SafeTransferLib` library to transfer the tokens to the sender. 

Please note that this is a basic implementation and might need to be adjusted based on the specific requirements and conditions of your escrow contract. For example, you might want to add additional checks to ensure that the withdrawal conditions have been met before allowing the withdrawal.


## Assessed type

Token-Transfer
The contract does not track the total supply of the liquidity pool tokens. This could allow the pool to artificially mint tokens without additional deposits in order to manipulate the token price
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
This allows manipulating the price without additional deposits.

## Proof of Concept
The contract does not track the total supply of the liquidity pool tokens. This could allow the pool to artificially mint tokens without additional deposits in order to manipulate the token price

The vulnerability comes from the fact that _calculatePrice relies only on the maxDeposit and maxMint values from the orderbook mapping to determine the price
An attacker could:
1. Make a small initial deposit to set maxDeposit and maxMint
2. Call LiquidityPoolLike.mint directly to mint additional tokens without making further deposits
3. The inflated maxMint value would reduce the calculated _calculatePrice


## Tools Used
Manual
## Recommended Mitigation Steps
the contract needs to track the total token supply separately from maxMint


## Assessed type

Other