code-423n4 / 2023-03-mute-findings

2 stars 1 forks source link

An attacker can lower the price of another depositor() by frontrunning #12

Closed code423n4 closed 1 year ago

code423n4 commented 1 year ago

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 to maxPrice linearly in terms of the amount of elapsed time since epochStart.

function bondPrice() public view returns (uint) {
        uint timeElapsed = block.timestamp - epochStart;
        uint priceDelta = maxPrice - startPrice;

        if(timeElapsed > epochDuration)
          timeElapsed = epochDuration;

        return timeElapsed.mul(priceDelta).div(epochDuration).add(startPrice);
    }

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.

c4-judge commented 1 year ago

Picodes marked the issue as duplicate of #24

c4-judge commented 1 year ago

Picodes marked the issue as satisfactory

c4-judge commented 1 year ago

Picodes changed the severity to 3 (High Risk)