xanoutas/solidity-security-findings huggingface dataset:
Integration issue in ousgInstantManager with BUILD if minUSTokens is set by blackrock. 
Audit: 2024-03-ondo-finance-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/ousgInstantManager.sol#L459-L461


# Vulnerability details

## Impact
Integration issues with BUILD incase blackrock decides to set a minimum amount of BUILD tokens that should be held by its holders.

## Proof of Concept
Blackrock implements a ```minUSTokens;``` variable where it sets a minimum amount to be held by the whitelisted addresses at all times. This check is done at every transfer.
Currently this is set to 0. But this could be set by blackrock anytime. 
```javascript
    // get min us tokens 
    function getMinUSTokens() public view override returns (uint256) {
        return minUSTokens;
    }
    
    // set min us tokens  
    function setMinUSTokens(uint256 _value) public override onlyTransferAgentOrAbove {
        emit DSComplianceUIntRuleSet("minUSTokens", minUSTokens, _value);
        minUSTokens = _value;
    }
```
This is the code from the [```BUILD token's contracts/compliance/ComplianceConfigurationService.Sol```](https://etherscan.deth.net/token/0x7712c34205737192402172409a8f7ccef8aa2aec#code) where the admin could set values for minUSTokens. 


Also the line 238 in the [contracts/compliance/Compliance/ServiceRegulated.sol](https://etherscan.deth.net/token/0x7712c34205737192402172409a8f7ccef8aa2aec#code) is called when transferring token.
```javascript
if (  
                _args.fromInvestorBalance > _args.value &&
                _args.fromInvestorBalance - _args.value < IDSComplianceConfigurationService(_services[COMPLIANCE_CONFIGURATION_SERVICE]).getMinUSTokens() 
            ) {
                return (51, AMOUNT_OF_TOKENS_UNDER_MIN);
            }
```
What this does is it essentially checks that the sender has atleast min amount of tokens after the transfer.

The probem is the ```ousgInstantManager``` doesn't require that it always has this much amount of BUILD. When redeeming suppose it has 300k BUILD and the minimum is say 10k BUILD and an investor in ondo wants to redeem 300k BUILD tokens it would still revert even though the contract has it. Which could unexpectedly revert violiating one the main functionalities for ondo i.e. the instant redeem. 



## code

create a new test file and paste this code below:
```solidity 
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {Test, console} from "forge-std/Test.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IBUILDPause {
    function pause() external;
    function isPaused() external returns(bool);
    
}

interface IBUiLDRedeemer {
    function redeem(uint256 amount) external;
}
// 0x1e695A689CF29c8fE0AF6848A957e3f84B61Fe69
contract testBUILD is Test {
    // holders of BUILD tokens; just for test 
    address holder1 = 0x72Be8C14B7564f7a61ba2f6B7E50D18DC1D4B63D;
    address holder2 = 0xEd71aa0dA4fdBA512FfA398fcFf9db8C49A5Cf72;
    address holder3 = 0xdc77C1D2A1dC61A31BE81e4840368DffEFA
Inadequate Handling of BUIDL Redemption Limit in OUSG Instant Manager
Audit: 2024-03-ondo-finance-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/ousgInstantManager.sol#L426-L429
https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/ousgInstantManager.sol#L460


# Vulnerability details

## Impact

The OUSG Instant Redemption Manager contract contains an oversight in its `redeem` function, specifically in the handling of BUIDL redemption limits. This oversight can potentially lead to failed redemption attempts when the redemption balance exceeds the BUIDL balance held by the manager contract while it has a right amount if its concatenated with USDC amount left by another redemption process. The impact of this issue is significant as it affects the usability of the redemption feature and can result in user frustration and loss of trust in the system.

## Proof of Concept

The following Proof of Concept (POC) demonstrates the issue, use it as part of `forge-tests/ousg/OUSGInstantManager/redeem.t.sol` file:

Run using this command

```bash
npm run test-forge -- --match-test test_POC_reddem_fail_when_alice_redeemtion_balance_is_over_manager_BUIDL_balance
```

```solidity
  function test_POC_reddem_fail_when_alice_redeemtion_balance_is_over_manager_BUIDL_balance()
    public
    setupSecuritize(500_000e6, 500_000e6)
  {    
    uint256 aliceOUSGRedeemAmount = 1667e18; 
    uint256 aliceUSDCAmount = 250_100e6;

    uint256 bobOUSGRedeemAmount = 1666e18;
    uint256 bobUSDCAmount = 249_900e6;


    // Mint OUSG tokens for Alice and Bob
    vm.prank(address(ousgInstantManager));
    ousg.mint(alice, aliceOUSGRedeemAmount);

    vm.prank(address(ousgInstantManager));
    ousg.mint(bob, bobOUSGRedeemAmount);

    // Bob redeems OUSG tokens successfully
    vm.startPrank(bob);
    ousg.approve(address(ousgInstantManager), (bobOUSGRedeemAmount));
    ousgInstantManager.redeem(bobOUSGRedeemAmount);
    vm.stopPrank();

    // Alice attempts to redeem OUSG tokens, but the redemption fails due to insufficient BUIDL balance
    vm.startPrank(alice);
    ousg.approve(address(ousgInstantManager), (aliceOUSGRedeemAmount));
    vm.expectRevert('Not enough tokens');
    ousgInstantManager.redeem(aliceOUSGRedeemAmount);
    vm.stopPrank();

    assertEq(USDC.balanceOf(bob), bobUSDCAmount);

    assertEq(
      BUIDL.balanceOf(address(ousgInstantManager)) + USDC.balanceOf(address(ousgInstantManager)),
      aliceUSDCAmount
    );

    // However if Alice try to reddem an amount that will be in usdc amount <= minBUIDLRedeemAmount in ousgInstantManager it will success
    vm.startPrank(alice);
    ousgInstantManager.redeem(aliceOUSGRedeemAmount - 10e18);
    vm.stopPrank();

    // Tokens remaining in Alice's balance after successful redemption
    assertEq(ousg.balanceOf(alice), 10e18);

  }
```

## Tools Used

- Manual review
- Foundry

## Recommended Mitigation Steps

To address this issue, the OUSG Instant Redemption Manager co
BURNER has permission to burn any amount from any account.
Audit: 2024-03-ondo-finance-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/rOUSG.sol#L618-L640


# Vulnerability details

## Impact
`BURNER` can burn any amount of the 'rOUSG' token from any account, resulting in the loss of assets for the users.

## Proof of Concept
https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/rOUSG.sol#L624-L640
```
  function burn(
    address _account,
    uint256 _amount
  ) external onlyRole(BURNER_ROLE) {
    uint256 ousgSharesAmount = getSharesByROUSG(_amount);
    if (ousgSharesAmount < OUSG_TO_ROUSG_SHARES_MULTIPLIER)
      revert UnwrapTooSmall();

    _burnShares(_account, ousgSharesAmount);

    ousg.transfer(
      msg.sender,
      ousgSharesAmount / OUSG_TO_ROUSG_SHARES_MULTIPLIER
    );
    emit Transfer(address(0), msg.sender, getROUSGByShares(ousgSharesAmount));
    emit TransferShares(_account, address(0), ousgSharesAmount);
  }
```
The `BURNER` has permission to burn any amount of the `rOUG` tokens and transfer the `OUSG` token to the `BURNER`. 
This poses a risk for users as they can lose their assets.
```
    ousg.transfer(
      msg.sender,
      ousgSharesAmount / OUSG_TO_ROUSG_SHARES_MULTIPLIER
    );
```
## Tools Used
Manual Review

## Recommended Mitigation Steps

We can mitigate this issue by fixing the code like this.
```
  function burn(
    address _account,
    uint256 _amount
  ) external onlyRole(BURNER_ROLE) {
    uint256 ousgSharesAmount = getSharesByROUSG(_amount);
    if (ousgSharesAmount < OUSG_TO_ROUSG_SHARES_MULTIPLIER)
      revert UnwrapTooSmall();

    _burnShares(_account, ousgSharesAmount);

    ousg.transfer(
      _account,
      ousgSharesAmount / OUSG_TO_ROUSG_SHARES_MULTIPLIER
    );
  }
```



## Assessed type

Access Control
Missing Declaration of Return Value from rousg.transferFrom 
Audit: 2024-03-ondo-finance-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/ousgInstantManager.sol#L362-L385
https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/rOUSG.sol#L276-L387


# Vulnerability details

## Impact
The redeemRebasingOUSG function does not declare or capture the return value from rousg.transferFrom, potentially leading to unintended consequences.

The rousg.transferFrom function transfers tokens but does not check or capture the return value.
If the transfer fails (e.g., due to insufficient allowance), the contract will not be aware of it.

## Proof of Concept
The vulnerability arises from the following aspect of the code:

```solidity
function redeemRebasingOUSG(
    uint256 rousgAmountIn
  )
    external
    override
    nonReentrant
    whenRedeemNotPaused
    returns (uint256 usdcAmountOut)
  {
    require(
      rousg.allowance(msg.sender, address(this)) >= rousgAmountIn,
      "OUSGInstantManager::redeemRebasingOUSG: Insufficient allowance"
    );
    rousg.transferFrom(msg.sender, address(this), rousgAmountIn);
    rousg.unwrap(rousgAmountIn);
    uint256 ousgAmountIn = rousg.getSharesByROUSG(rousgAmountIn) /
      OUSG_TO_ROUSG_SHARES_MULTIPLIER;
```
this is the tranferFrom function from the rousg token contract.
```solidity
 function transferFrom(
    address _sender,
    address _recipient,
    uint256 _amount
  ) public returns (bool) {
    uint256 currentAllowance = allowances[_sender][msg.sender];
    require(currentAllowance >= _amount, "TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE");

    _transfer(_sender, _recipient, _amount);
    _approve(_sender, msg.sender, currentAllowance - _amount);
    return true;
  }
```
## Tools Used
Manual review
## Recommended Mitigation Steps
Capture the return value from rousg.transferFrom and handle any potential errors (e.g., revert the transaction if the transfer fails).





## Assessed type

Library
multiexcall on empty array can result in loss of funds
Audit: 2024-03-ondo-finance-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/ousgInstantManager.sol#L794-L811
https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/rOUSGFactory.sol#L121-L132


# Vulnerability details

## Impact
In both rOUSGFactory and ousgInstantManager, the function multiexcall() allows a guardian to execute batched calls. However given the structure of the function, if an empty array is supplied, the for loop will be skipped. If any ETH was sent during the function call then it would lost and locked in the contract.

Given that the function is privileged the risk of this scenario happening is lower than that of a unprivileged function but the risk stills exists and would result in a loss of funds for whoever called it.

## Proof of Concept
Reference links to affected code

## Tools Used
Manual Review

## Recommended Mitigation Steps
Implement a check for array length greater than 0 and create a way to extract ETH/tokens from the contract.


## Assessed type

Loop
Bad smart contract could cause whole transaction to revert 
Audit: 2024-03-ondo-finance-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/rOUSGFactory.sol#L121-L132


# Vulnerability details

## Impact
Address of bad smart contract could fail transfer of value to other targets.

## Proof of Concept
Let's assume smart contract in which 'revert()' is used in fallback() and receive().
Now whenever rOUSGFactory.sol tries to transfer value to that bad smart contract it will revert and prevent other addresses to receive value.

## Tools Used
Manual review.

## Recommended Mitigation Steps
Make sure the address of such a smart contract won't get added in exCallData





## Assessed type

DoS
`ROUSG` Contract's `getOUSGPrice` Lacks Protection Against Erroneous Oracle Data
Audit: 2024-03-ondo-finance-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/rOUSG.sol#L378-L380


# Vulnerability details

The `ROUSG` contract's `getOUSGPrice` function lacks a sanity check to validate the price returned by the oracle, potentially exposing the contract to risks if the oracle provides incorrect data or in case of Oracle malfunction.

## Impact
Without a sanity check, the contract could accept an incorrect price, which would affect balance and total supply, and the calculation of `rOUSG` token amounts during `wrap` and `unwrap` operations. This could lead to incorrect token balances, allowing users to wrap or unwrap amounts that do not reflect the true market value of `OUSG`, potentially resulting in financial loss.

## Proof of Concept
The `getOUSGPrice` function in the `ROUSG` contract is defined as follows:
```solidity
    function getOUSGPrice() public view returns (uint256 price) {
        (price, ) = oracle.getPriceData();
}
```
[Link to the code: ROUSG.sol#getOUSGPrice](https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/rOUSG.sol#L378C1-L380C4)

In contrast, the ousgInstantManager.sol contract includes a sanity check to ensure the price is not unexpectedly low:
```solidity
    function getOUSGPrice() public view returns (uint256 price) {
        (price, ) = oracle.getPriceData();
        require(
        price > MINIMUM_OUSG_PRICE,
        "OUSGInstantManager::getOUSGPrice: Price unexpectedly low"
        );
    }
```
[Link to the code: ousgInstantManager.sol#getOUSGPrice](https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/ousgInstantManager.sol#L479C1-L485C4)

The absence of a similar check in the ROUSG contract could lead to the aforementioned impact.

## Tools Used
Manual Review

## Recommended Mitigation Steps
Implement a sanity check in the `ROUSG` contract's `getOUSGPrice` function similar to the one found in the `ousgInstantManager.sol` contract. This check should ensure the price is within a reasonable range and not unexpectedly low.


## Assessed type

Invalid Validation
Oracle feed can become obsolete due to lack of checks when using `Oracle feeds.`
Audit: 2024-03-ondo-finance-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/rOUSG.sol#L378


# Vulnerability details

## Impact
The function `getOUSGPrice` is used to get the oracle price of the `OUSG`  but the returned oracle `price feed` was not checked for weither price is stale.
```solidity
 function getOUSGPrice() public view returns (uint256 price) { 
    (price, ) = oracle.getPriceData();
  }
```
this can lead to loss of funds for the users redeeming their `rebasingOUSG` if the price feed is below the current price of the `OUSG`, or the protocol funds will be lost if the price is higher than the real price. This issue can be magnified if a malicious user purposely makes huge redeem when the price difference is high.

## Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

## Tools Used
Manual Review
## Recommended Mitigation Steps
check that the `oracle price feed` is not stale by checking that the price feed timestamp is not  greater tha the `max price update window` before using the price to calculate the amount of OUSG to redeem.


## Assessed type

Oracle
Approval race condition vulnerability in `rOUSG` token implementation
Audit: 2024-03-ondo-finance-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/rOUSG.sol#L276
https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/ousgInstantManager.sol#L375
https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/ousgInstantManager.sol#L317
https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/ousgInstantManager.sol#L348


# Vulnerability details

## Impact
This could result in an unexpected loss of tokens for the signer if their approval change is front-run after a transferFrom call.

The rOUSG token implementation deployed by the ROUSGFactory contract is vulnerable to approval front-running due to directly calling transferFrom without first setting the allowance to zero.

When transferFrom is called, it deducts the transfer amount from the caller's allowance of the from address's tokens. However, if the caller did not first set the allowance to zero, another party could call approve to front-run the decreased allowance amount after the transferFrom.


## Proof of Concept

Account A approves Account B some amount > 0
Account B calls transferFrom on behalf of Account A for some amount <= approved amount
Before the allowance is decreased, another party calls approve on behalf of Account A
This allows front-running the decreased allowance amount


## Tools Used

Manual Review

## Recommended Mitigation Steps

The rOUSG implementation should use OpenZeppelin's safeApprove/safeIncreaseAllowance functions which first set the allowance to zero before increasing to avoid this race condition.




## Assessed type

ERC20
redeemPaused and mintPaused could be out of sync causing users to be able to mint tokens but not be able to redeem them afterwards
Audit: 2024-03-ondo-finance-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/ousgInstantManager.sol#L756-L765


# Vulnerability details

## Impact
`ousgInstantManager` has 2 separate access control modifiers and boolean values for `redeemPaused` and `mintPaused`. In the event where the person with the `PAUSER_ROLE` decides to pause the redeem functionality but leaves out the mint functionality, users would still be able to freely mint tokens but will not be able to redeem them afterwards, thus having their funds in a way locked.

## Proof of Concept
Since `ousgInstantManager` has 2 boolean values which are `redeemPaused` and `mintPaused` as well as 2 setter functions for it, that means that they could be out of sync.

Imagine the following scenario:
1. Person who has `PAUSER_ROLE` pauses the redeem functionality due to a bug.
2. Bob sees the protocol and decides that he want to mint some tokens.
3. Time passes and Bob decides he wants to redeem those tokens.
4. Since the redeem functionality is paused, he is unable to do so and is left with the tokens he minted.

## Tools Used
Manual Review

## Recommended Mitigation Steps
Have a single boolean value, a single modifier and a single setter function for both the redeem and minting functionality.


## Assessed type

Access Control
Incompatibility with Account Abstraction Wallets Due to USDC Fee Deduction
Audit: 2024-03-ondo-finance-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/ousgInstantManager.sol#L458-L470


# Vulnerability details

## Impact
Users with AAWs may be unable to `redeem` if fees are deducted from the same `USDC balance`.
Potential DoS for AAW users if the `USDC` balance check fails.

## Proof of Concept
The rising popularity of AAWs means more users could encounter redemption issues, impacting the contract's accessibility and reliability.[More details here](https://dune.com/sixdegree/account-abstraction-overview)

Example issue with `_redeemBUIDL`:

A user initiates a redemption through an AAW, choosing to pay transaction fees in `USDC`. The AAW dispatches the redemption transaction, activating `_redeemBUIDL`. This function redeems `BUIDL` for `USDC`, swaps `BUIDL` for `USDC`, and transfers `USDC` to the `ousgInstantManager` contract. It then verifies whether the `USDC` balance has precisely increased by the `buidlAmountToRedeem`.

However, the AAW also pays the gas fee from the same `USDC` balance.

The final USDC balance is less than expected `(usdcBalanceBefore + buidlAmountToRedeem)` due to the fee deduction.
```javascript
    require(
      usdc.balanceOf(address(this)) == usdcBalanceBefore + buidlAmountToRedeem,
      "OUSGInstantManager::_redeemBUIDL: BUIDL:USDC not 1:1"
    );
```
The require statement fails, and the transaction reverts, even though the redemption was successful.

## Tools Used
Manual Review

## Recommended Mitigation Steps

1. Modify _redeemBUIDL to account for fee deductions in the USDC balance check.
2. Separate fee payments from redemption funds.
3. Implement pre-transaction estimations for fees and adjust the balance check accordingly.


## Assessed type

Other
Redemption Limitation Issue in ousgInstantManager.sol that Could Lead to Investors' OUSG Stuck in the Contract
Audit: 2024-03-ondo-finance-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/ousgInstantManager.sol#L402-L406


# Vulnerability details

## Impact
The issue presents a significant challenge in the redemption mechanism, particularly when an investor's remaining USDC redemption limit is inadvertently less than the minimum redemption threshold. This scenario can lead to a situation where an investor's funds (tracked by OUSG/rOUSG) become effectively "stuck" until the value of the underlying share assets increases sufficiently to meet the minimum redemption amount. The impact of this issue can vary depending on the frequency of such occurrences and the volume of affected transactions. It can lead to liquidity constraints for investors, diminish investor confidence due to perceived inflexibility and lack of liquidity, and introduce operational complexities for both investors and system administrators. 

## Proof of Concept
Here's a typical scenario based on the default settings of the contract,

https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/ousg/ousgInstantManager.sol#L110

```solidity
minimumRedemptionAmount = 50_000e6
```
and, a hypothetical rate limit:

[instantRedemptionLimit](https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/InstantMintTimeBasedRateLimiter.sol#L157-L160) = 1_000_000e6
[currentInstantRedemptionAmount](https://github.com/code-423n4/2024-03-ondo-finance/blob/main/contracts/InstantMintTimeBasedRateLimiter.sol#L135) = 935_000e6

1. Bob, the investor, has 110_000e6 USDC redeemable based on his OUSG balance of  1_000e18 where `getOUSGPrice() == 110e18`.
2. Bob is in need of an urgent liquid emergency and is forced to redeem the permissible 1_000_000e6 - 925_000e6 = 75_000e6 USDC.
3. Bob is now stuck with 35_000e6 USDC until OUSG increases in price where the 35_000e6 USDC could inflate to 50_000e6 USDC. 

## Tools Used
Manual

## Recommended Mitigation Steps
Consider allowing redemption if the investor's `usdcAmountToRedeem` being less than `minimumRedemptionAmount` is all the investor has after being converted from the OUSG shares.


## Assessed type

Context