Kelp DAO | rsETH - boredpukar'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: 125/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
QA (Quality Assurance)
sufficient quality report
duplicate-723
Q-76

External Links

Lines of code

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

Vulnerability details

Impact

The getRSETHPrice() function calculates the RSETH/ETH exchange rate based on the total value of assets in the LRT deposit pool, derived from individual asset prices fetched by getAssetPrice(), which in turn relies on Chainlink.

The function is potentially vulnerable to price manipulation if the oracle feeds can be tampered with, or if the pool balances can be artificially inflated, such as through a flash loan attack.

This price outrages provide a substantial attack surface for the protocol therefore it's worth adding some complexity to the current implementation.

Proof of Concept

function getRSETHPrice() external view returns (uint256 rsETHPrice) { address rsETHTokenAddress = lrtConfig.rsETH(); uint256 rsEthSupply = IRSETH(rsETHTokenAddress).totalSupply(); if (rsEthSupply == 0) { return 1 ether; } uint256 totalETHInPool; address lrtDepositPoolAddr = lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL); address[] memory supportedAssets = lrtConfig.getSupportedAssetList(); uint256 supportedAssetCount = supportedAssets.length; for (uint16 asset_idx; asset_idx < supportedAssetCount;) { address asset = supportedAssets[asset_idx]; uint256 assetER = getAssetPrice(asset); uint256 totalAssetAmt = ILRTDepositPool(lrtDepositPoolAddr).getTotalAssetDeposits(asset); totalETHInPool += totalAssetAmt * assetER; unchecked { ++asset_idx; } } return totalETHInPool / rsEthSupply; }

The oracle vulnerability can be exploited if an attacker finds a way to manipulate the data feed of the oracle service. For instance, by exploiting a vulnerability in the chainlink data feed.

An attacker could also take a substantial loan of a supported asset, deposits it into the LRT deposit pool, calls getRSETHPrice() to get an inflated price, and then uses this inflated price for profit in other transactions within the same block before repaying the flash loan.

Tools Used

Manual Review

Consider querying both the Chainlink oracle and Uniswap pool (TWAP implementation ) for latest prices, ensuring that these two values are within some upper/lower bounds of each other.

Slabbed under Medium risk as the function of the protocol or its availability could be impacted, or leak value with a hypothetical attack path with stated assumptions.

Assessed type

Oracle

#0 - c4-pre-sort

2023-11-16T05:00:08Z

raymondfam marked the issue as sufficient quality report

#1 - c4-pre-sort

2023-11-16T05:00:14Z

raymondfam marked the issue as duplicate of #32

#2 - c4-pre-sort

2023-11-17T05:04:48Z

raymondfam marked the issue as not a duplicate

#3 - c4-pre-sort

2023-11-17T05:04:59Z

raymondfam marked the issue as duplicate of #194

#4 - c4-pre-sort

2023-11-17T07:36:38Z

raymondfam marked the issue as duplicate of #723

#5 - c4-judge

2023-12-01T17:38:31Z

fatherGoose1 changed the severity to QA (Quality Assurance)

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