Kelp DAO | rsETH - marchev's results

A collective DAO designed to unlock liquidity, DeFi and higher rewards for restaked assets through liquid restaking.

General Information

Platform: Code4rena

Start Date: 10/11/2023

Pot Size: $28,000 USDC

Total HM: 5

Participants: 185

Period: 5 days

Judge: 0xDjango

Id: 305

League: ETH

Kelp DAO

Findings Distribution

Researcher Performance

Rank: 148/185

Findings: 1

Award: $2.76

QA:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

2.7592 USDC - $2.76

Labels

bug
downgraded by judge
grade-b
high quality report
primary issue
QA (Quality Assurance)
sponsor disputed
edited-by-warden
Q-104

External Links

Lines of code

https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/oracles/ChainlinkPriceOracle.sol#L38 https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTOracle.sol#L68-L71

Vulnerability details

Impact

The rsETH price calculation contains a vulnerability which allows users to deposit assets and receive rsETH of much higher value than the deposited assets.

Proof of Concept

In the Kelp protocol, when users deposit assets using LRTDeposit#depositAsset(), they get rsETH in exchange of their deposited assets.

The _mintRsETH() is called in depositAsset() to mint the new rsETH a user would receive. The amount of minted rsETH is based on the deposited asset's amount and exchange rate using getRsETHAmountToMint():

https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTDepositPool.sol#L108-L109

The rsETH price is calculated in LRTOracle#getRSETHPrice():

https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTOracle.sol#L52-L76

In essence, the rsETH price calculation is performed via the following formula:

rsETH Price=(A1×P2)+(A2×P2)+ ... +(Ai×Pi)rsETH Total SupplyrsETH\ Price = \frac{(A_1 \times P_2) + (A_2 \times P_2) + \ ...\ + (A_i \times P_i)}{rsETH\ Total\ Supply}

where,

$A_{1, 2,\ ...\ ,i}$ = The total asset deposits for each asset

$P_{1, 2,\ ...\ ,i}$ = The price of each asset

However, a known fact is that the Chainlink oracle's latestAnswer() function can return 0 instead of an error if no answer has been reached. This flaw can be exploited.

For example, if the oracle erroneously reports 0 for an asset, a user depositing another asset might receive more rsETH than usual. The severity of this issue varies based on the assets in the protocol and which asset has the oracle error.

To illustrate, consider a scenario with 100 stETH, 100 rETH, and 100 cbETH in the protocol. For simplicity, let's assume the price for both rETH and cbETH is 1 ETH. If the oracle fails for stETH, reporting 0 as the price, and Alice deposits 50 rETH, she would get approximately 75.75e18 rsETH instead of the 50e18 she would receive under normal conditions.

rsETH Tokens=50×rETH PricersETH PricersETH\ Tokens = \frac{50 \times rETH\ Price}{rsETH\ Price}

where

$rETH\ Price = 1e18$

$rsETH\ Price = \frac{100 \times 0 + 100 \times 1e18 + 100 \times 1e18}{300} \approx 0.66e18$

Thus,

rsETH Tokens=50×1e180.66e18≈75.75e18rsETH\ Tokens = \frac{50 \times 1e18}{0.66e18} \approx 75.75e18

In the absence of an error with the Chainlink price oracle, Alice would have received:

rsETH Tokens=50×1e18100×1e18+100×1e18+100×1e18300=50e181=50e18rsETH\ Tokens = \frac{50 \times 1e18}{\frac{100 \times 1e18 + 100 \times 1e18 + 100 \times 1e18}{300}} = \frac{50e18}{1} = 50e18

The potential for exploitation here hinges on the asset mix in the protocol and the specific asset affected by the oracle error.

Tools Used

Manual review

Revert if AggregatorInterface#latestAnswer() returns 0:

--- a/src/oracles/ChainlinkPriceOracle.sol
+++ b/src/oracles/ChainlinkPriceOracle.sol
@@ -35,7 +35,9 @@ contract ChainlinkPriceOracle is IPriceFetcher, LRTConfigRoleChecker, Initializa
     /// @param asset the asset for which exchange rate is required
     /// @return assetPrice exchange rate of asset
     function getAssetPrice(address asset) external view onlySupportedAsset(asset) returns (uint256) {
-        return AggregatorInterface(assetPriceFeed[asset]).latestAnswer();
+        uint256 assetPrice = AggregatorInterface(assetPriceFeed[asset]).latestAnswer();
+        require(assetPrice != 0, "Oracle price error");
+        return assetPrice;
     }

     /// @dev add/update the price oracle of any supported asset

Alternatively, use latestRoundData() from the Chainlink Data Feeds API.

Assessed type

Oracle

#0 - c4-pre-sort

2023-11-16T01:15:18Z

raymondfam marked the issue as sufficient quality report

#1 - c4-pre-sort

2023-11-16T01:15:27Z

raymondfam marked the issue as duplicate of #32

#2 - c4-pre-sort

2023-11-17T05:31:26Z

raymondfam marked the issue as not a duplicate

#3 - c4-pre-sort

2023-11-17T05:31:32Z

raymondfam marked the issue as primary issue

#4 - c4-pre-sort

2023-11-17T07:40:03Z

raymondfam marked the issue as high quality report

#5 - c4-sponsor

2023-11-24T09:25:09Z

gus-staderlabs (sponsor) disputed

#6 - gus-stdr

2023-11-24T09:26:25Z

#7 - c4-judge

2023-11-29T19:26:11Z

fatherGoose1 marked the issue as unsatisfactory: Invalid

#8 - c4-judge

2023-12-04T17:45:53Z

fatherGoose1 changed the severity to QA (Quality Assurance)

#9 - marchev

2023-12-06T17:34:51Z

Dear contest judge,

I am writing to respectfully request a re-evaluation of the severity classification of this finding. I believe that my finding, currently classified as a QA issue, merits a higher severity rating, specifically as a Medium severity issue.

Here is my reasoning:

  1. In light of the inaugural Supreme Court session in Fall 2023, it is acknowledged that the acceptance of reports based on automated findings is subject to the judge's discretion. However, as detailed in the Supreme Court Decisions (Code4rena Supreme Court Decisions, Fall 2023), there is a recognition that in certain circumstances, the severity of findings based on bot findings can be considered for elevation. This sets a precedent for reconsideration in cases like this one.

  2. It is crucial to note that my finding is distinct from those identified during the Bot Race phase. My analysis and interpretation of the issue extend beyond the scope of automated discovery, providing a more nuanced understanding of the vulnerability.

  3. The core of my argument lies in the material impact of the security issue I have identified. This vulnerability results in a tangible, material loss for the protocol, which is a defining characteristic of a Medium severity issue. Unlike the report generated by the Bot, my submission delineates the impact of the vulnerability, emphasizing why it poses a significant risk that warrants immediate attention.

Given these points, I kindly request that you reconsider the severity rating of my finding. The material impact of the issue, coupled with the guidance from the Supreme Court Decisions, supports the reclassification of this finding to a Medium severity issue.

Thank you for your time and consideration in this matter!

#10 - fatherGoose1

2023-12-08T18:49:29Z

@marchev I will not be upgrading this finding. The chainlink oracle returning a value of 0 would be highly unlikely, and would likely be mitigated if Kelp moved away from using the latestAnswer() function as highlighted by the bot. There is not enough in this report to warrant an upgrade.

#11 - c4-judge

2023-12-08T18:52:03Z

fatherGoose1 marked the issue as grade-b

#12 - marchev

2023-12-09T14:17:53Z

Thanks for looking into it, @fatherGoose1!

Regards, Martin

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter