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
Rank: 148/185
Findings: 1
Award: $2.76
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: m_Rassska
Also found by: 0x1337, 0xAadi, 0xHelium, 0xLeveler, 0xblackskull, 0xbrett8571, 0xepley, 0xffchain, 0xluckhu, 0xmystery, 0xrugpull_detector, 0xvj, ABAIKUNANBAEV, Aamir, AerialRaider, Amithuddar, Bauchibred, Bauer, CatsSecurity, Cryptor, Daniel526, Draiakoo, Eigenvectors, ElCid, GREY-HAWK-REACH, Inspecktor, Juntao, King_, LinKenji, Madalad, MaslarovK, Matin, MatricksDeCoder, McToady, Noro, PENGUN, Pechenite, Phantasmagoria, RaoulSchaffranek, SBSecurity, SandNallani, Shaheen, Soul22, Stormreckson, T1MOH, Tadev, TeamSS, TheSchnilch, Topmark, Tumelo_Crypto, Udsen, Yanchuan, ZanyBonzy, _thanos1, adeolu, adriro, alexfilippov314, almurhasan, amaechieth, anarcheuz, ayden, baice, bareli, boredpukar, bronze_pickaxe, btk, cartlex_, catellatech, chaduke, cheatc0d3, circlelooper, codynhat, crack-the-kelp, critical-or-high, debo, deepkin, desaperh, dipp, eeshenggoh, evmboi32, ge6a, gesha17, glcanvas, gumgumzum, hals, hihen, hunter_w3b, jasonxiale, joaovwfreire, ke1caM, leegh, lsaudit, marchev, merlinboii, niser93, osmanozdemir1, paritomarrr, passion, pep7siup, phoenixV110, pipidu83, poneta, ro1sharkm, rouhsamad, rvierdiiev, sakshamguruji, seerether, shealtielanz, soliditytaker, spark, squeaky_cactus, stackachu, supersizer0x, tallo, taner2344, turvy_fuzz, twcctop, ubl4nk, wisdomn_, xAriextz, zach, zhaojie, zhaojohnson, ziyou-
2.7592 USDC - $2.76
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
The rsETH price calculation contains a vulnerability which allows users to deposit assets and receive rsETH of much higher value than the deposited assets.
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()
:
The rsETH price is calculated in LRTOracle#getRSETHPrice()
:
In essence, the rsETH price calculation is performed via the following formula:
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.
where
$rETH\ Price = 1e18$
$rsETH\ Price = \frac{100 \times 0 + 100 \times 1e18 + 100 \times 1e18}{300} \approx 0.66e18$
Thus,
In the absence of an error with the Chainlink price oracle, Alice would have received:
The potential for exploitation here hinges on the asset mix in the protocol and the specific asset affected by the oracle error.
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.
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:
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.
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.
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