Detailed description of the impact of this finding.
The deposit() function will bump bond price back by 5% after purchase based on current delta.
However, this function can be executed unlimited number of times in the same block and as a result, one can exploit this vulnerability to attack another depositor: he can lower the price of another depositor() to the lowest by frontrunning.
Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.
We show how an attacker can lower the price of another depositor() by frontrunning:
1) The bondPrice will increase the price of the bond from startPrice to maxPrice linearly in terms of the amount of elapsed time since epochStart.
2) Meanwhile, the deposit() function will bump bond price back by 5% after purchase based on current delta.
// adjust price by a ~5% premium of delta
uint timeElapsed = block.timestamp - epochStart;
epochStart = epochStart.add(timeElapsed.mul(5).div(100));
// safety check
if(epochStart >= block.timestamp)
epochStart = block.timestamp;
3) However, there is no restriction in terms how many times deposit() can be called in one block. So an attacker can call it many times (say 50 times) to lower the price of the bond (0.95^50 = 0.0762).
4) Suppose Alice sees a good price of the bond, so she decides she will buy the bond.
5) Attacker Bob comes a long and call deposit() 50 times (with the minimum 0.01e18 payout) and reduce the price near startPrice() (see implementation of bondPrice()).
6) As a result, Alice purchased the bond with a very lower price and she is not happy with the result.
Tools Used
VSCode
Recommended Mitigation Steps
1) We will make sure within each block the price can be bumped back at most once.
2) We need to have some slippage control for the depositor so that the depositor will get the minium amount of payout for the input lptoken.
Lines of code
https://github.com/code-423n4/2023-03-mute/blob/4d8b13add2907b17ac14627cfa04e0c3cc9a2bed/contracts/bonds/MuteBond.sol#L153-L200
Vulnerability details
Impact
Detailed description of the impact of this finding. The
deposit()
function will bump bond price back by 5% after purchase based on current delta. However, this function can be executed unlimited number of times in the same block and as a result, one can exploit this vulnerability to attack another depositor: he can lower the price of another depositor() to the lowest by frontrunning.Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.
We show how an attacker can lower the price of another depositor() by frontrunning:
1) The bondPrice will increase the price of the bond from
startPrice
tomaxPrice
linearly in terms of the amount of elapsed time sinceepochStart
.2) Meanwhile, the
deposit()
function will bump bond price back by 5% after purchase based on current delta.3) However, there is no restriction in terms how many times
deposit()
can be called in one block. So an attacker can call it many times (say 50 times) to lower the price of the bond (0.95^50 = 0.0762).4) Suppose Alice sees a good price of the bond, so she decides she will buy the bond.
5) Attacker Bob comes a long and call deposit() 50 times (with the minimum 0.01e18 payout) and reduce the price near
startPrice()
(see implementation ofbondPrice()
).6) As a result, Alice purchased the bond with a very lower price and she is not happy with the result.
Tools Used
VSCode
Recommended Mitigation Steps
1) We will make sure within each block the price can be bumped back at most once.
2) We need to have some slippage control for the depositor so that the depositor will get the minium amount of payout for the input lptoken.