When the first user enters, totalSupply is set to 1e18.
if (totalSupply == 0)
return 1 ether;
else return totalETHInPool / rsEthSupply;
But the user can immediately withdraw most of his rsETH such that totalSupply << 1e18. The attacker can then increase the totalETHInPool by transferring supported assets to the LRTDepositPool contract.
For subsequent users, the getRSETHPrice will be heavily inflated ,
The calculation of rsethAmountToMint = (amount * lrtOracle.getAssetPrice(asset)) / lrtOracle.getRSETHPrice()
can be very inaccurate. In the worst case it rounds down to 0 for users that deposit a value that is less than the value that the attacker transferred in.
Proof of Concept
1.attacker/first depositor mint 10 rsETH and immediately removes all but kept 1 wei.
2.Attacker then directly transfer 10 ETH worth of an asset in LRTDepositPool.
3.When the second user calls the function depositAsset with 5 ETH worth of an asset amount(less than 10 ETH worth of an asset amount), no additional rsETH are minted since rsethAmountToMint is rounded down to 0.
Impact
The first user that stakes can manipulate the total supply of rsETH and by doing so create a rounding error for each subsequent user. In the worst case, an attacker can steal all the funds of the next user.
Lines of code
https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTOracle.sol#L78 https://github.com/code-423n4/2023-11-kelp/blob/main/src/LRTDepositPool.sol#L109
Vulnerability details
summary
When the first user enters, totalSupply is set to 1e18.
if (totalSupply == 0) return 1 ether; else return totalETHInPool / rsEthSupply; But the user can immediately withdraw most of his rsETH such that totalSupply << 1e18. The attacker can then increase the totalETHInPool by transferring supported assets to the LRTDepositPool contract.
For subsequent users, the getRSETHPrice will be heavily inflated , The calculation of rsethAmountToMint = (amount * lrtOracle.getAssetPrice(asset)) / lrtOracle.getRSETHPrice() can be very inaccurate. In the worst case it rounds down to 0 for users that deposit a value that is less than the value that the attacker transferred in.
Proof of Concept
1.attacker/first depositor mint 10 rsETH and immediately removes all but kept 1 wei. 2.Attacker then directly transfer 10 ETH worth of an asset in LRTDepositPool. 3.When the second user calls the function depositAsset with 5 ETH worth of an asset amount(less than 10 ETH worth of an asset amount), no additional rsETH are minted since rsethAmountToMint is rounded down to 0.
Impact
The first user that stakes can manipulate the total supply of rsETH and by doing so create a rounding error for each subsequent user. In the worst case, an attacker can steal all the funds of the next user.
Tools Used
manual review
Assessed type
Math