xanoutas/solidity-security-findings huggingface dataset:
Price manipulation attack
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/PriceFeed.sol#L557


# Vulnerability details

## Impact
The PriceFeed.sol was marked OOS but I believe this to be a valid issue. If the chainlink feed fails which is does from time to time, the Tellor price feed takes over no matter what the delta is compared to the chainlink price. This is an issue because the Tellor price feed can be manipulated by a malicious attacker who

1.. Stakes the min amount of TRB tokens to become a reporter
2.. Reports an inflated price.

After the price of collateral is inflated an attacker can mint extra LUSD tokens. On the other hand the attacker could also drop the price below the MCR and liquidate everyone on the protocol. BonqDAO was recently hacked in this exact same way.

## Proof of Concept
Add the following test to PriceFeedTest

```
it.only("Tellor set max price", async () => {
    await setAddresses()
    // --- Chainlink fails, system switches to Tellor ---
    const statusBefore = await priceFeed.status(collateral1.address)
    assert.equal(statusBefore, '0') // status 0: Chainlink working

    // Chainlink breaks with negative price
    await mockChainlink.setPrevPrice(dec(1, 8))
    await mockChainlink.setPrice("-5000")

    await mockTellor.setPrice(dec(123, 18))
    await mockChainlink.setUpdateTime(0)

    const priceFetchTx = await priceFeed.fetchPrice(collateral1.address)
    const statusAfter = await priceFeed.status(collateral1.address)
    assert.equal(statusAfter, '1') // status 1: using Tellor, Chainlink untrusted

    let price = await priceFeed.lastGoodPrice(collateral1.address)
    assert.equal(price, dec(123, 18))

    // Tellor is able to set price to max uint256
    await mockTellor.setPrice('115792089237316195423570985008687907853269984665640564039457584007913129639935')
    await priceFeed.fetchPrice(collateral1.address)
    price = await priceFeed.lastGoodPrice(collateral1.address)
    // Check Liquity PriceFeed gives 0.0001 with 18 digit precision
    assert.equal(price, '115792089237316195423570985008687907853269984665640564039457584007913129639935')
  })
```
add this test to BorrowOperationsTest

```
it.only("Manipulates the price up and mints inflated amoounts of tokens", async () => {
      // alice creates a Trove and adds first collateral
      await openTrove({ collateral: collaterals[0], ICR: toBN(dec(2, 18)), extraParams: { from: alice } })
      await openTrove({ collateral: collaterals[0], ICR: toBN(dec(10, 18)), extraParams: { from: bob } })

      // Pump price after compromising tellor manipulation
      await priceFeed.setPrice(collaterals[0].address, dec(100, 48))
      const price = await priceFeed.getPrice(collaterals[0].address)

      const LUSDwithdrawal = toBN(dec(10, 28))  // withdraw 10**28 LUSD

     await borrowerOperations.withdrawLUSD(collaterals[0].address, th._100pct, LUSDwithdrawal, alice, alice, { from: alice }) 
     
     c
`CommunityIssuance` doesn't check the return value of `OathToken.transferFrom()` and `OathToken.transfer()`
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/LQTY/CommunityIssuance.sol#L103
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/LQTY/CommunityIssuance.sol#L127


# Vulnerability details

## Impact
The function `CommunityIssuance.fund()` calls `OathToken.transferFrom()` but doesn't check the return value, which indicates whether the transfer succeeded or failed. Similarly, the function `CommunityIssuance.sendOath()` calls `OathToken.transfer()` but doesn't check the return value, which indicates whether the transfer succeeded or failed.

Because of these two issues, LQTY gains may not be send to users (by the `StabilityPool`), if for example the owner didn't set a correct allowance before initially calling `CommunityIssuance.fund()`.

## Recommended Mitigation Steps
Check the return value.
ReaperVaultERC4626.sol is not EIP-4626 compliant
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultERC4626.sol#L12-L276


# Vulnerability details

## Impact
Other protocols integrated with Ethos Reserve may mistakenly assume that its function complies with EIP-4626. Therefore, this may lead to integration issues in the future, which could result in various problems for both parties.

## Proof of Concept
All official EIP-4626 requirements can be found on it's https://eips.ethereum.org/EIPS/eip-4626#methods official page. Non-compliant functions are listed below along with the reason they are not compliant:

The following functions are missing but should be present:

mint(uint256, address) returns (uint256)
redeem(uint256, address, address) returns (uint256)
The following functions are non-compliant because they don't account for withdraw and deposit locking:

-maxDeposit
-maxMint
-maxWithdraw
-maxRedeem

All of the above functions should return 0 when their respective functions are disabled (i.e. maxDeposit should return 0 when deposits are disabled)

previewDeposit is not compliant because it must account for fees which it does not

totalAssets is not compliant because it does not always return the underlying managed by the vault because it fails to include the assets paid out during a depeg or the end of the epoch.
## Tools Used

## Recommended Mitigation Steps
All functions listed above should be modified to meet the specifications of EIP-4626
ReaperBaseStrategyv4 is not Initializable
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/abstract/ReaperBaseStrategyv4.sol#L14
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L62
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L19


# Vulnerability details

## Impact
ReaperStrategyGranarySupplyOnly calls function __ReaperBaseStrategy_init() from ReaperBaseStrategyv4, 
but ReaperBaseStrategyv4 is not Initializable. If the __ReaperBaseStrategy_init function is not called during contract initialization, it can cause critical issues as the state variables initialized in this function won't be set properly. This can lead to unexpected behavior and vulnerabilities such as reentrancy, funds being stuck in the contract, or even complete loss of funds.

For example, if "want" is not initialized properly, the contract may not be able to interact with the expected token and may result in users' funds being locked in the contract indefinitely. 
Similarly, if roles are not initialized properly, it can result in unauthorized access to sensitive functions or funds.

## Recommended Mitigation Steps

Recommended steps: Add Initializable to contract declaration.

```
abstract contract ReaperBaseStrategyv4 is
    ReaperAccessControl,
    IStrategy,
    UUPSUpgradeable,
    AccessControlEnumerableUpgradeable,
    "Initializable"
{
```
Contract not initialized after deployment
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L19
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperStrategyGranarySupplyOnly.sol#L62
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/abstract/ReaperBaseStrategyv4.sol#L63
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/CollateralConfig.sol#L46


# Vulnerability details

## Impact
In ReaperStrategyGranarySupplyOnly.sol, the initialize function is not called after deployment. 
Left open to unintended behaviour and/or an attacker calling the initialize function, gaining control of 
core permissions and functions, as highlighted in the __ReaperBaseStrategy_init.


## Tools Used
Manually checked through.


## Recommended Mitigation Steps

Recommended steps:

```
constructor(address _vault, address[] memory _strategists, address[] memory _multisigRoles, IAToken _gWant) {
    initialize(_vault, _strategists, _multisigRoles, _gWant);
}

modifier onlyOwner() {
    require(msg.sender == owner(), "Ownable: caller is not the owner");
    _;
}

function initialize(address _vault, address[] memory _strategists, address[] memory _multisigRoles, IAToken _gWant) 
    public initializer onlyOwner {
    gWant = _gWant;
    want = _gWant.UNDERLYING_ASSET_ADDRESS();
    __ReaperBaseStrategy_init(_vault, want, _strategists, _multisigRoles);
    rewardClaimingTokens = [address(_gWant)];
}
```
LQTYStaking.sol – Reentrancy risk in stake() unstake() functions 
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LQTY/LQTYStaking.sol#L104


# Vulnerability details

In the LQTY smart contract, the stake() and unstake() functions are used to add or remove a certain amount of LQTY tokens from a user's stake, respectively. Both functions are designed to update the user's stake and the total amount of LQTY staked while allowing users to withdraw any accumulated gains in collateral and LUSD tokens.

The unstake() function is vulnerable to reentrancy attacks. This means that a malicious attacker could call the unstake() function and then call a fallback function on a malicious contract that could immediately call the unstake() function again before the initial call is completed, leading to a reentrancy attack. 

To mitigate this vulnerability, the following should be considered:

-Use a mutex to prevent multiple simultaneous calls to the unstake() function.

-Implement the checks-effects-interactions pattern, where all checks are performed before any external interactions are made. This will ensure that the state of the contract is updated before any external calls are made, preventing any potential reentrancy attacks.

-Limit the amount of LQTY tokens that can be unstaked at any given time. This will limit the potential damage caused by a reentrancy attack and allow for easier recovery in the event of an attack.
ActivePool.sol – Re-entrancy risk on _rebalance function 
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/ActivePool.sol#L239


# Vulnerability details

The `_rebalance` function is vulnerable to a reentrancy attack. Specifically, an external callee can take over the control flow of the function by calling back into the `ActivePool` contract via a method that triggers the `_rebalance` function again before it completes the execution of its current invocation. If this happens, the attacker can execute additional logic in the context of the partially executed `_rebalance` function, bypass some checks and extract additional funds. 

Since the `_rebalance` function updates and reclaims funds from external contracts such as `yieldGenerator` contract and LQTY's `StabilityPool` contract, reentrancy attacks can enable attackers to steal additional funds than they are entitled to. For example, an attacker can repeatedly withdraw their profits from the `yieldGenerator` during the attack and bypass the check that examines the performance fees. 

Solution: To mitigate this vulnerability, the `_rebalance` function should be designed as a non-reentrant function to ensure that it completes the execution of its current invocation before allowing a new one to begin. One way to achieve this is by using the OpenZeppelin's `ReentrancyGuard` library or a similar technique.

manual review
Integer Overflow & Underflow
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Core/contracts/ActivePool.sol#L144


# Vulnerability details

## Impact
In the setYieldDistributionParams function, there is a danger of underflow or overflow of functionality. 
Owner calls the function and sets the values to be passed as uint256 for _treasurySplit, _SPSplit & _stakingSplit.
There is no check in place to ensure that the inputs for each variable are within the range of uint256.
Plus this function can be called more than once. This can lead to underflow or overflow of functionality and even a DoS. 

## Proof of Concept
Mythril output:

==== Integer Arithmetic Bugs ====
SWC ID: 101
Severity: High
Contract: ActivePool
Function name: setYieldDistributionParams(uint256,uint256,uint256)
PC address: 4176
Estimated Gas Usage: 17171 - 78323
The arithmetic operator can overflow.
It is possible to cause an integer overflow or underflow in the arithmetic operation. 
--------------------
In file: ActivePool.sol:180

_treasurySplit + _SPSplit

--------------------
Initial State:

Account: [CREATOR], balance: 0x0, nonce:0, storage:{}
Account: [ATTACKER], balance: 0x0, nonce:0, storage:{}

Transaction Sequence:

Caller: [CREATOR], calldata: , decoded_data: , value: 0x0
Caller: [CREATOR], function: setYieldDistributionParams(uint256,uint256,uint256), txdata: 0x46a80441fb99ff79e30f9d682000000000000000000000000000000000000000000000c0fb009e1dc4bec56f6421086b300625284f9f84200a42400000000000000026500965626858319d287bdef794cff9dad7b0607bdff5bdc0000000000000000000, decoded_data: (113802615826695248396852422504501212897875946311553853527583929208779141284032, 113531616272880797637669467260555445576659233119585921170888059337521819035216, 4249946375056344812620080252319157232004789900141353380443179469525298970624), value: 0x0



==== Integer Arithmetic Bugs ====
SWC ID: 101
Severity: High
Contract: ActivePool
Function name: setYieldDistributionParams(uint256,uint256,uint256)
PC address: 4177
Estimated Gas Usage: 17171 - 78323
The arithmetic operator can overflow.
It is possible to cause an integer overflow or underflow in the arithmetic operation. 
--------------------
In file: ActivePool.sol:180

_treasurySplit + _SPSplit + _stakingSplit

--------------------
Initial State:

Account: [CREATOR], balance: 0x0, nonce:0, storage:{}
Account: [ATTACKER], balance: 0x0, nonce:0, storage:{}

Transaction Sequence:

Caller: [CREATOR], calldata: , decoded_data: , value: 0x0
Caller: [CREATOR], function: setYieldDistributionParams(uint256,uint256,uint256), txdata: 0x46a80441220000000000000000000000000000000000000000000000000000000000245e22101b1eff8777c2bfffffffffffffffffffffffffffffffffffffffffffe2babbefe4e10078883d400000000000000000000000000000000000000000001ff8, decoded_data: (15378636851831057204693021446466362761762419838405387411490460376050962539614, 15407093587727637316092311883187679068048045558716129932169709548489431573178, 85006358797757500902785
StabilityPool.sol – Re-entrancy risk on withdrawfromSP() 
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/StabilityPool.sol#L389


# Vulnerability details

The withdrawFromSP function in the StabilityPool contract is vulnerable to a reentrancy attack through the _sendLUSDToDepositor function. 

The _sendLUSDToDepositor function is vulnerable because it transfers LUSD tokens and LQTY gains before updating state variables, which could allow an attacker to repeatedly call the function and drain the pool. An attacker could deploy a malicious contract with a fallback function that calls the _sendLUSDToDepositor function repeatedly, potentially leading to a loss of LUSD tokens in the pool.

To mitigate this risk, the withdrawFromSP function could be updated to use the "Checks-Effects-Interactions" pattern, where all state variables are updated before any external contracts are called. This would prevent an attacker from being able to repeatedly call the _sendLUSDToDepositor function and drain the pool of LUSD tokens. 

Additionally, the withdrawFromSP function could implement a reentrancy guard to prevent multiple calls to the same function during execution.

https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/StabilityPool.sol#L389
Incorrect Price-Feed Failsafe System
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L203
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L211
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L224
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L230
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L241
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L247
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L284
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L291
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L309
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L318
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L324
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L334
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L338
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L351
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L370
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L375
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/PriceFeed.sol#L388


# Vulnerability details

## Impact

The default behavior of the `PriceFeed` contract is to fallback to the latest reported price by the Chainlink and Tellor oracles it supports. 

This behavior is ill-advised as an oracle reporting its prices improperly indicates a significant and potentially fatal market event. Similar implementations in use during the LUNA price crash suffered from significant bad debt, including:
- Venus Protocol: https://blog.venus.io/venus-protocol-official-statement-regarding-luna-6eb45c3cb058
- Blizz Finance: https://rekt.news/venus-blizz-rekt/

To note, those protocols were affected because the Chainlink oracle was paused thereby reporting the same stale price over and over. The exact behavior would result in the same outcome in the Ethos Reserve ecosystem as an oracle would be considered "frozen" in such a case and cause the contract to yield the latest "good price".

## Proof of Concept

The code below demonstrates how a price will be "static" if the Chainlink oracle of a token fails:
```sol
contract ImproperStalePrice {
    uint256 public price;
    uint256 public lastReport;

    // This parameter can be arbitrarily configured and showcases that any amount of time can elapse
    uint256 private constant STALENESS_WINDOW = 1 hours;

    /**
     * Simplified Assumptions:
     *
     * - Contract Is Owner of `PriceFeed`
     */
    fu
The _allocBPS field from strategy struct can be 0 this will make the strategy irrevocable
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L144-L171


# Vulnerability details

## Impact
No sanity check will make a strategy irrevocable

## Proof of Concept
The addStrategy function can be used to add a strategy, there are multiple sanity checks inside the function however there is missing a very important one, there is no check for _allocBPS != 0, so at the moment the _allocBps for a strategy could be 0, this will break the contract invariant because the revokeStrategy function is checking is a strategy allocBps is 0, is it is 0, then the function will return without doing anything so the strategy will be irrevocable.


https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L144-L171

https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultV2.sol#L210-L212

## Tools Used
Manual review

## Recommended Mitigation Steps
Add a sanity check in addStrategy function that will check for _allocBps != 0
Inexistent Prevention of Duplicates
Audit: 2023-02-ethos-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/CollateralConfig.sol#L56-L73
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/StabilityPool.sol#L626-L635
https://github.com/code-423n4/2023-02-ethos/blob/main/Ethos-Core/contracts/LQTY/LQTYStaking.sol#L203-L211


# Vulnerability details

## Impact

The `CollateralConfig::initialize` function which instantiates the contract's state does not prevent duplicate collateral entries from being specified which can occur undetected.

If the system is setup with duplicate collateral entries, the `Ethos Core` codebase will significantly misbehave with the following indicative examples:

- `StabilityPool::getDepositorCollateralGain` - The collateral gains will be counted twice for each depositor, causing them to withdraw double the rewards on a first-come-first-serve basis with late parties / the last individual being unable to withdraw at all
- `LQTYStaking::_getPendingCollateralGain` - The pending collateral gains will be counted twice for each depositor here as well in a similar way to the above scenario

Based on historical C4 judging of [duplicate-entry findings that affect assets](https://github.com/code-423n4/2023-02-kuma-findings/issues/13), this finding is at minimum a medium-severity issue. Given that the issue can remain undetected during the contract's initial setup and is only identified during withdrawals rather than deposits, it is conceivable that assets would be potentially compromised with a higher likelihood than the duplicate-entry finding referenced by this exhibit.

As a result, I have classified this w/ a high-severity given its significant impact and possibility to exploit without privileged access.

## Proof of Concept

Here is a demonstration of how the vulnerability will cause the last staker to be unable to withdraw their stake:

```sol
contract DuplicateEntryExploit {
    /**
     * Simplified Assumptions: 
     *
     * - Contract Possesses 1e18 LQTY Token Units
     * - Contract Possesses 1e18 Collateral Token Units
     * - Contract Is Owner of `CollateralConfig`
     * - Contract Is Trove Manager / Redemption Helper / Active Pool of `LQTYStaking`
     * - Staking Contract Has Been Initialized Properly
     */
    function demonstrate(IERC20 collateral, ILQTYStaking staking, ICollateralConfig config) external {
        // Flaw: Initialize `CollateralConfig` w/ Duplicate Entry
        config.initialize([collateral, collateral], [2 ether, 2 ether], [2 ether, 2 ether]);

        // Step 1: Stake LQTY in `LQTYStaking`
        staking.lqtyToken().approve(address(staking), 1 ether);
        staking.stake(1 ether);

        // Step 2: Transfer Rewards & Report Gain
        collateral.transfer(address(staking), 1 ether);
        staking.increaseF_Collateral(address(collateral), 1 ether);

        // Step 3: Attempt Withdrawal of Rewards
        try staking.unstake(1 ether) {
            revert("Unreachable");