code-423n4 / 2024-04-renzo-findings

9 stars 7 forks source link

Intrinsic arbitrage between oracle price deviations #424

Closed howlbot-integration[bot] closed 3 months ago

howlbot-integration[bot] commented 4 months ago

Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L507 https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Withdraw/WithdrawQueue.sol#L229

Vulnerability details

Impact

A discrepancy in oracle price deviation between two assets can be exploited for arbitrage; one can deposit the relatively overvalued asset and withdraw for the relatively undervalued asset.

Proof of Concept

The price of ezETH is based on a sum of oracle prices of multiple assets. The oracles will be slightly inaccurate; in the case of the Chainlink stETH/ETH feed the deviation threshold is 0.5%, which means that it may be up to 0.5% more or less than the true price. The deposit is valued according to the oracle price, and so is the amount of tokens received on withdrawal.

Suppose 2000 ezETH has been minted against 1000 tokA and 1000 tokB, and that the current true prices of tokA and tokB are 1. However, suppose the oracle returns a price of tokA as 1.005 and of tokB as 0.997. This means that ezETH will be priced at (1005 + 997) / 2000 = 1.001 An attacker can exploit this by depositing tokA and withdrawing tokB. Suppose the attacker buys 100 tokA for 100 ETH (according to its true price) and deposits this. This will be valued as 100 * 1.005 = 100.5 ETH by the oracle and he will get 100.5 / 1.001 ≈ 100.4 ezETH. (This does not change the price of ezETH.) If he then immediately withdraws the ezETH, but now for tokB, he will get a value of 100.4 * 1.001 = 100.5 ETH, which in tokB is–according to the oracle–100.5 / 0.997 ≈ 100.8 tokB, which is also truly worth 100.8 ETH. The attacker was thus able to acquire 100.8 ETH worth of tokB by depositing only 100 ETH worth of tokA.

Recommended Mitigation Steps

Note that this attack depends on a differential deviation between assets. It would not work if there was only one asset, or if they deviate identically. The maximum extractable value in percentage is the maximum possible deviation between any two assets. Consider eliminating the profitability of this attack by taking exactly this percentage as a fee on either deposit of withdrawal, e.g. if the deviation threshold of tokA is 0.5% and of tokB is 0.3% then charge a 0.8% fee. This fee might either be taken by the protocol or just implemented as a reduced amount of ezETH minted or tokens withdrawn, effectively returning it to other holders.

Assessed type

MEV

c4-judge commented 4 months ago

alcueca marked the issue as duplicate of #326

c4-judge commented 4 months ago

alcueca marked the issue as satisfactory

d3e4 commented 3 months ago

@alcueca The root cause of #326 is the pricing of withdrawals on withdraw instead of on the delayed claim (e.g. here and here). Note my other issue #239 which is correctly duplicated to #326 on this basis.

This issue (#424), on the other hand, is not based on either the pricing on withdraw instead of claim, nor the delay, nor on sandwiching an oracle update. Rather, it is a static issue that arises when tokenizing a sum of price feeds. It can only be mitigated by a pessimistic valuation, effectively charging a fee on withdrawal. The originary report of this kind of issue might be helpful (note however that it also deals with the additional complication that it was not possible to freely choose which asset to deposit or withdraw).

c4-judge commented 3 months ago

alcueca marked the issue as not a duplicate

alcueca commented 3 months ago

@jatinj615, please review. You might consider this expected behaviour, but same as #13 arbitrage opportunities of this kind should be avoided. I also see fees on withdrawals as a more elegant and doable solution to prevent MEV and arbitrage than pricing withdrawals upon claiming.

c4-judge commented 3 months ago

alcueca marked the issue as primary issue

jatinj615 commented 3 months ago

@alcueca , thanks for pointing out the arbitrage issue. Some pointers which needs to be considered at the current state of the protocol from our side -

Acknowledging for now.

c4-judge commented 3 months ago

alcueca marked the issue as selected for report

c4-judge commented 3 months ago

alcueca marked the issue as duplicate of #13

c4-judge commented 3 months ago

alcueca marked the issue as not selected for report

alcueca commented 3 months ago

Given that the root cause is the use of market rates for stEth, this becomes a uplicate of #13

c4-judge commented 3 months ago

alcueca changed the severity to 2 (Med Risk)

d3e4 commented 3 months ago

@alcueca Why was this lowered to Medium and duplicated to #13 (/deselected as best)?

I'm not sure if this has been properly understood, but #424 has nothing to do with frontrunning an oracle update. #429 is only based on frontrunning an oracle update, and #13 is only based on frontrunning an update of an stETH depeg.

424, on the other hand, exploits the ever present deviations in the oracle price from the true market price (as acknowledged by the Chainlink oracle).

The root cause of #424 is not the use of the market rate; rather, being able to use the true market rate would completely eliminate the arbitrage discussed in #424.

13 is quite vaguely written, but it seems to lack any proof to distinguish it from #429. The first part of its PoC is just a sequence of trades stETH -> ezETH, price change, ezETH -> stETH, just as reported by #429. The second part seems to be essentially the same thing: ETH -> ezETH, price change, ezETH -> stETH. Only by invoking a second asset could it be connected to #424, in which case it has to be interpreted that "stETH market depegs" is not reflected in the oracle price feed. This information is missing, however.

It turns out the price change in ezETH can only effectively happen if it is based on more than a single underlying asset, otherwise the price of ezETH would just be a fictitious conversion factor (as long as the vault is otherwise fairly implemented). However, #13 and #429 make no mention of, nor seem to be aware, this fact; they simply seem to be based on the idea of the price's changing and to exploit this as a possibility to predict the "future" for a winning trade.

13 and #429 can be said to describe an arbitrage over time, which is not really an arbitrage in the usual sense but a regular trade. The issue in this context is that because of the oracle price update and mempools we can exploit this to predict the future, which is not possible in regular real-time trading.

424 instead describes an arbitrage between two underlying assets. Because of the oracle price deviation the multiple asset vault enables a true arbitrage due to mispricing between its assets. This mispricing is generally present, and whenever two assets are mispriced in opposite ways there is an immediate and unavoidable arbitrage opportunity between them which will persist (at least) until the oracle price updates.

alcueca commented 3 months ago

All these issues are quite similar in that there is an arbitrage opportunity in the way that ezETH is minted based on oracle prices, which invariably deviate from the true value of ezETH, whatever that might be.

13 shows that using the stETH/ETH market price deviates from the stETH/ETH exchange rate price.

428, #429, and #613 show that the stETH/ETH oracle price deviates from the market price.

424, #425, #246 and #247 show that the ezETH/ETH price on deposit deviates from the market price of the collaterals used to mint it.

All these cases are mitigated, at least partially, by locking in the withdrawals queue the LSTs without producing yield for the cooldown period. All these cases would be mitigated by applying deposit or withdrawal fees. Several other mitigations, like delays on deposits, or pricing withdrawals at the time of claim, would likely address all of these findings equally.

Based on this, and how all the findings seem to draw from the same past contests and protocols, I'm inclined to consider them a group.

I also have the impression that the sponsor was not unaware of these issues, but that probably didn't consider them to be serious enough to warrant more serious defensive measures. None of these issues has proven beyond doubt that they would have a serious impact on the protocol. Based on that, I think that a Medium severity is fair.