xanoutas/solidity-security-findings huggingface dataset:
Same Address can participated at a same time to win the fighter.
Audit: 2024-02-ai-arena-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-02-ai-arena/blob/cd1a0e6d1b40168657d1aaee8223dc050e15f8cc/src/MergingPool.sol#L118-L132


# Vulnerability details

## Impact
As mentioned in the contract there will be only two winners in a single period. So there should be two different users who can win this otherwise one can participate with their account multiple times and it will lead to a bad impact . As that user can mint multiple fighters at a same time without losing any points. 
In the ``function pickWinner()`` there is an array input which takes two inputs and it select winner but here if same address is passed at index 0 and at index 1 Both will get different fighter respectively

## Proof of Concept
**Run this code in the MergingPool.t.sol**
It shows that same address can be passed to pick winner.
```
// @audit
    function testPickWinnerSameAddress() public {
        _mintFromMergingPool(_ownerAddress);
        _mintFromMergingPool(_ownerAddress);
        assertEq(_fighterFarmContract.ownerOf(0), _ownerAddress);
        assertEq(_fighterFarmContract.ownerOf(1), _ownerAddress);
        // assertEq(_fighterFarmContract.ownerOf(1), _DELEGATED_ADDRESS);
        uint256[] memory _winners = new uint256[](2);
        _winners[0] = 0;
        _winners[1] = 1;
        // vm.expectRevert("Address should not be same.");
        _mergingPoolContract.pickWinner(_winners);
        assertEq(_mergingPoolContract.isSelectionComplete(0), true);
        assertEq(_mergingPoolContract.winnerAddresses(0, 0) == _ownerAddress, true);
        assertEq(_mergingPoolContract.winnerAddresses(0, 1) == _ownerAddress, true);
        // assertEq(_mergingPoolContract.winnerAddresses(0, 1) == _DELEGATED_ADDRESS, true);
    }
```

## Tools Used
Foundry 

## Recommended Mitigation Steps
There should be a check to mitigate that the address passed is not same as address at index 0 and address at index 1.


## Assessed type

Payable
Expired members can lose their tranche tokens if they call `transferTrancheTokensToCentrifuge` or `transferTrancheTokensToEVM` in `PoolManager.sol` 
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/PoolManager.sol#L149-L163
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/PoolManager.sol#L136-L147


# Vulnerability details

## Impact
User can call `transferTrancheTokensToCentrifuge` or `transferTrancheTokensToEVM` to transfer their tranche tokens to other chains, but no verifying is done to see if they are expired members or not on the source chain, which can cause loss of funds for some users.

## Proof of Concept
The function `handleTransferTrancheTokens` that is called on the destination chain is verifying if the receiver address is a expired or active member 
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/PoolManager.sol#L272-L275
but no checks are done on the source chain when the transfer is made 
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/PoolManager.sol#L136-L147
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/PoolManager.sol#L149-L163
which can lead to loss of funds for a user which membership has expired and he doesn't know. Since the member system is time-based, users can get expired and still call `transferTrancheTokensToCentrifuge` or `transferTrancheTokensToEVM` which will burn their tokens, but the transfer will be blocked on the destination chain, causing loss of funds for the users.

## Tools Used
Manual review
## Recommended Mitigation Steps
Consider checking for active members in the source chain transfer functions also to mitigate the loss of funds for the users.


## Assessed type

Other
requestDeposit and requestRedeem do not allow for any price guarantee, opening users to sandwich attacks and other losses
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#L231-L234


# Vulnerability details

## Impact

Request functions take only the desired input amount as a parameter, giving no way for the caller to control the fulfilment price. The price is decided by the Centrifuge mainnet only.
```
    function requestDeposit(uint256 assets, address owner);
    function requestRedeem(uint256 shares, address owner); 
```

If there is anyway for an attacker to affect the price, eg. front running the request, manipulating an oracle used by Centrifuge or if the transaction get’s delayed users will be loosing funds.

Given the asynchronous nature of the system and it’s reliance on 3rd party bridges there are many scenarios in which a significant delay may happen for example:
- bridge outage
- tx getting priced out
- insufficient liquidity on Centrifuge
- other

I'd like to reiterate that is a potential loss that cannot be prevented by the user and which is also largely not controlled by the protocol. Furthermore it is not following the de facto DEFI standard. 

Note on severity: It could be argued that users using the platform will implicitly agree to this risk, on the other side it is highly likel that many users will be simply chose not to use it. I would argue that 
it would render the protocol largely unuseable.

## Tools Used
Manual review.
## Recommended Mitigation Steps
Add `minAmountOut` and `deadline` in the requestDeposit and requestRedeem  as well as downstream from them, including the Centrifuge order book.
```
    function requestDeposit(uint256 assets, address owner, uint256 minAmountOut, uint256 deadline)
```


## Assessed type

MEV
Some Outgoing functions are not supported on the gateway
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
The gateway serves both outgoing and incoming calls, All incoming calls should have corresponding outgoing calls and vice versa
However, some incoming calls like ``addPool()`` , ``allowPoolCurrency()`` , ``addTranche()`` have no corresponding calls via the gateway contract. They cannot be sent.
Some outgoing calls like ``increaseRedeemOrder()`` have no corresponding incoming call.
This is particularly an issue because all this calls have their individual ``message`` type, hence could lead to DOS when trying to receive this functions.

## Proof of Concept
All calls here cannot be mapped  1 -> 1 , hence some of the incoming functions in handle cannot be sent 
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/gateway/Gateway.sol#L200-L366

## Tools Used
Manual Review. 
## Recommended Mitigation Steps
Examine all functions and make sure they all have sender functions and Receiver functions


## Assessed type

Error
Incorrent approval for escrow tokens, not allowing to burn on redeem
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
Liquidity pool approval for burning escrow tokens is not correctly assigned when pool is deployed on `PoolManager` `deployLiquidityPool` lines:

```
        EscrowLike(escrow).approve(liquidityPool, address(investmentManager), type(uint256).max); // Approve investment manager on tranche token for coordinating transfers
        EscrowLike(escrow).approve(liquidityPool, liquidityPool, type(uint256).max); // Approve liquidityPool on tranche token to be able to burn
```

wich causes the burn of said token later on the proces to not execute on `InvestmentManager` `handleExecutedCollectInvest()`:

```
        LiquidityPoolLike(liquidityPool).burn(address(escrow), trancheTokensPayout); // burned redeemed tokens from escrow
```
## Proof of Concept
After calling `deployLiquidityPool()` wich should give max allowance on escrow assets to `InvestmentManager` and `liquidityPool` you can check the allowance[escrow][liquiditypool] = 0.

## Tools Used
Manual review, Remix


## Recommended Mitigation Steps

I'd suggest writting approval directly on token on lines as this mid step makes the pool msg.sender and not escrow:

```
        EscrowLike(escrow).approve(liquidityPool, address(investmentManager), type(uint256).max); // Approve investment manager on tranche token for coordinating transfers
        EscrowLike(escrow).approve(liquidityPool, liquidityPool, type(uint256).max); // Approve liquidityPool on tranche token to be able to burn
```


## Assessed type

ERC20
lack of failsafe mechanism to replay the failed transaction between source chain and destination chain. This would lead to loss of funds to user when transaction is failed.
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L69
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/routers/axelar/Router.sol#L24
https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/gateway/Messages.sol#L8


# Vulnerability details

## Impact

When the transaction fails in any of chain ( source or destination), it never be replayed. This would lead to loss of assets if the the transaction is target for token transfer. Similarly other issue can happen.

## Proof of Concept
Centrifuge used the cross chain messaging mechanism to connect with different chain with centrifuge chain.

The message (transaction payload) is built in source chain and relayed to destination chain. In destination chain the transaction is completed.

For example, the tokens are burnt or locked in the source chain and event is emitted and this message is relayed to destination chain. The destination chain either mint new tokens or do some other functionality depend on user request.

when the transaction fails on the destination chain, it left silently. One possible reason could be, due to spike in gas price, the transaction would revert on the destination chain.

As an example we can see the [handleExecutedCollectRedeem](https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/InvestmentManager.sol#L255), which is initiated in source chain by Manager contract. 

Before calling the gateway contract, tokens transaction and burning is done.

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

After this, the message is relayed to destination chain and then the token minting is or asset transfer will be done.

But, when the transaction fails on the destination chain, they will not be replayed again. 

## Tools Used

Manual review.

## Recommended Mitigation Steps

We recommend to capture the failed transactions and replay.  or, collect those failed transaction and notify the user by emitting event. So that they can be allowed to redo the transaction.





## Assessed type

Error
Malicious RestrictionManger can be used to verify Tranche Members
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/512e7a71ebd9ae76384f837204216f26380c9f91/src/token/Tranche.sol#L42-L46


# Vulnerability details

The ability to file a new Restriction Manger after deployment can actually be utilized by a rouge ward and deploy a malicious version of the `RestrictionManger` that implements almost the same thing as the originals, but just tweaked to return the SUCCESS_MESSAGE and the SUCCESS CODE that will enable anyone to be able to invest and redeem in a tranche that they are not a member of. Lets look at a security breach situation
The protocol is initially configured with a trusted `restrictionManager` contract, which enforces specific transfer restrictions as intended by the protocol's design.
A rogue ward, let's call them Bob, gains access to the protocol's governance. Bob has the authority to execute changes in the protocol's settings
Bob decides to use the file function to change the address of the `restrictionManager` contract to a malicious contract that he controls or influences.
Bob's malicious contract implements tweaked functionality. For example, it could set the transfer restriction to always return the success code, effectively allowing anyone to invest and redeem tokens without being a member of the intended tranche.
With this malicious `restrictionManager` in place, Bob can manipulate token operations, allowing unauthorized transfers and potentially causing financial losses to token holders.


## Proof of Concept
```
function file(bytes32 what, address data) public auth {
        if (what == "restrictionManager") restrictionManager = ERC1404Like(data);
        else revert("TrancheToken/file-unrecognized-param");
        emit File(what, data);
    }
```
In the `Factory.sol` contract you can clearly see from this code that a rouge ward can actually change the `restrictionManger` and deploy a malicious contract in its place, to achieve the aim of the attack of the attacker.

## Recommended Mitigation Steps

I have an idea to be able to prevent this incase all other protocol wards can't react to the rouge wards on time
A time lock mechanism on when the restriction manager contract can be changed and replaced if there was ever a need or any other system has to be put in place to avoid changing such a critical system at will.



## Assessed type

DoS
Allowance manipulation in UserEscrow struct leads to unauthorized token transfers due to overreliance on maximum allowance check
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-09-centrifuge/blob/main/src/UserEscrow.sol#L36-L50


# Vulnerability details

## Summary

The `UserEscrow` smart contract contains a vulnerability that can possibly allow unauthorized users to transfer tokens out of the contract. Specifically, an attacker can exploit this flaw by manipulating the allowances, thus enabling them to bypass the authorization checks present within the `transferOut` function.

## Vulnerability Detail

The `transferOut` function in the `UserEscrow` contract makes use of a conditional check, where if a receiver's allowance, as set in the `token` contract for a given `destination`, equals `type(uint256).max`, then the function will permit the transfer of tokens. This paradigm relies heavily on the flawed premise that setting an allowance to the maximum possible uint256 value inherently implies trustworthiness or consent for a transfer.

However, there are notable concerns as while using this approach:

1. **Arbitrary allowance setting**: A malicious user can purposely set their allowance (for their own account) to this maximum value. By doing so, they can deceive the function into believing that the `destination` has given them the right to transfer tokens, even if no such intention or approval was given.

2. **Lack of true intent validation**: Merely because an allowance is set to `type(uint256).max` doesn't necessarily indicate that the `destination` wanted the `receiver` to have control over their tokens. It could simply be a user setting a high allowance for convenience, to avoid frequently resetting allowances, or even by mistake.

3. A crafty attacker can detect users who've set high allowances and manipulate the `UserEscrow` contract to illegitimately extract tokens.

> e. g.:

- Alice, unaware of such vulnerabilities, sets her allowance for Bob to `type(uint256).max` on a separate platform.
- Bob, realizing this, then deposits some of his own tokens into the `UserEscrow`.
- Now, Bob attempts to transfer tokens from Alice's account within the `UserEscrow` using the `transferOut` function. Given that the allowance check will pass (since Alice's allowance for Bob is `type(uint256).max`), Bob successfully transfers Alice's tokens, even though she never intended for him to access her tokens within the `UserEscrow`.

The critical flaw is the presumption that an allowance of `type(uint256).max` is a definitive and irrefutable sign of trust, when in reality, it might not be. As seen in the below mentioned POC, this vulnerability can be exploited to result in unauthorized transfers, causing eventual loss of tokens for unsuspecting users.

> To further clarify, as per the logic intended within the following comments:

```
/// @dev transferOut can only be initiated by the destination address or an authorized admin.
///      The check is just an additional protection to secure destination funds in case of compromized auth.
///      Since userEscrow is not able to decrease th
Access Control Dependency on `msg.sender`: The `onlyGateway` modifier relies solely on `msg.sender` for access control. If the address of the gateway contract is compromised or manipulated, it can lead to unauthorized access to critical functions within the contract.
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

### Access Control Dependency on `msg.sender`

**Impact:** The `onlyGateway` modifier relies solely on `msg.sender` for access control. If the address of the gateway contract is compromised or manipulated, it can lead to unauthorized access to critical functions within the contract.

**Proof of Concept:** In the provided contract code, the `onlyGateway` modifier is used to restrict access to specific functions to the gateway contract. However, it solely depends on the caller's address (i.e., `msg.sender`) matching the address of the gateway contract.

Here's an example of the `onlyGateway` modifier:

```solidity
modifier onlyGateway() {
    require(msg.sender == address(gateway), "PoolManager/not-the-gateway");
    _;
}
```

This modifier allows access to certain functions only if `msg.sender` is equal to the address of the `gateway` contract. If an attacker were to compromise the `gateway` contract's address or manipulate the caller's address, they could potentially gain unauthorized access to critical functions, which is a security risk.

**Recommended Mitigation Steps:** To enhance access control and mitigate the risks associated with relying solely on `msg.sender`, consider implementing a more robust access control mechanism, such as role-based access control (RBAC). RBAC allows for fine-grained control over who can perform specific actions within the contract.

Here are the recommended steps to mitigate this issue:

1. Implement a Role-Based Access Control System: Create different roles within your contract, such as `gatewayRole`, and assign specific addresses (contracts) to these roles.

2. Modify Functions to Check Roles: Instead of relying on `msg.sender`, modify the functions to check if the caller (contract) has the required role. For example:

   ```solidity
   modifier onlyGateway() {
       require(hasRole(gatewayRole, msg.sender), "PoolManager/not-the-gateway");
       _;
   }
   ```

3. Grant Roles to Authorized Contracts: Ensure that only authorized contracts are granted the necessary roles using a controlled and secure process.

By implementing RBAC or a similar access control mechanism, you can reduce the risk of unauthorized access to critical functions, even if the address of the gateway contract is compromised or manipulated.


## Assessed type

Access Control
Unchecked Input
Audit: 2023-09-centrifuge-findings
Severity: HIGH

# Lines of code

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


# Vulnerability details

## Impact
Attackers can get the auth badge due to unchecked input vulnerability at the `LiquidityPool` The ward[msg.sender] badge gives the attacker the highest role in the entire Centrifuge ecosystem, allowing the attacker to steal funds and cause DOS.

## Proof of Concept
This is a step by step poc:
- An attacker calls a function like `requestDepositWithPermit` in the `LiquidityPool` with a malicious contract address having the permit function.
- The permit function in the contract calls another contract like `Root` on the function `relyContract`
- The permit function uses delegatecall to use the address of the `LiqudityPool` contract as the msg.sender bypassing the auth check modifier
- The `relyContract` approves the malicious contract with the appropriate target auth and user as the contract
- The function returns after the external call, the rest of the function reverts but the two external calls made still has the new changed state
- Malicious contract now have access to manipulate almost all contracts, functions and prices.

## Tools Used
Manual Review

## Recommended Mitigation Steps
- Use roles instead of centralized auth
- Check the asset address being called in the `requestDepositWithPermit` and similar


## Assessed type

Other