code-423n4 / 2024-01-opus-findings

0 stars 0 forks source link

The `provide()` function does not reset withdrawal requests, allowing an attacker to bypass risk-free yield tactics protection #116

Open c4-bot-8 opened 9 months ago

c4-bot-8 commented 9 months ago

Lines of code

https://github.com/code-423n4/2024-01-opus/blob/04583e0411dbf8027952d668a8678fda0cb5b160/src/core/absorber.cairo#L441

Vulnerability details

Impact

In the Opus protocol, the absorber is a stability pool that permits yin holders to contribute their yin and participate in liquidations (also known as absorptions) as a consolidated pool. Provided yin from users could be absorbed during an absorption. In return, users receive yang, which usually has a higher value than the absorbed yin. However, in the event of bad debt, it could be less. This situation could lead to risk-free yield frontrunning tactics, where an attacker only provides yin when the absorption brings profit then removing all yin right after that.

The Opus team is aware of this attack vector and has therefore implemented a request-withdraw procedure. Users must first request a withdrawal and wait for a certain period before executing the withdrawal.

However, the provide() method does not reset these request timestamps, which allows an attacker to bypass this safeguard.

Proof of Concept

The attacker's tactics will be:

  1. Deposit a small amount of yin into 100 of his accounts. Note that the total value of these small amounts is negligible. Also please note that the value 100 is just arbitrary value to describe the idea. It could be higher or lower depending on the REQUEST_BASE_TIMELOCK and REQUEST_VALIDITY_PERIOD.
  2. Regularly request withdrawals for these accounts to ensure that at least one account has a valid request at any given time. This can be easily achieved by requesting a withdrawal from the 1st account at timestamp X, the 2nd at X + REQUEST_VALIDITY_PERIOD, the 3rd at X + 2 * REQUEST_VALIDITY_PERIOD, and so on. The 1st account request will expire at X + REQUEST_BASE_TIMELOCK + REQUEST_VALIDITY_PERIOD, but now 2nd request account become valid because it has requested at X + REQUEST_VALIDITY_PERIOD.
  3. Since the provide() function does not reset the request, the attacker can simply select one account with a valid removing request and perform the "risk-free yield tactics". He does this by providing a large amount of yin to this account to earn yield and then immediately calling remove().

Tools Used

Manual Review

Recommended Mitigation Steps

Reset the withdrawal request in the provide() function.

Assessed type

MEV

c4-pre-sort commented 9 months ago

bytes032 marked the issue as sufficient quality report

c4-pre-sort commented 9 months ago

bytes032 marked the issue as primary issue

c4-sponsor commented 8 months ago

tserg (sponsor) confirmed

c4-sponsor commented 8 months ago

tserg marked the issue as disagree with severity

tserg commented 8 months ago

The economic feasibility of the exploit is questionable, and it requires extensive infra to be set up and maintained. Ultimately, no user funds are at risk.

alex-ppg commented 8 months ago

The Warden has demonstrated how a malicious user can game the queued withdrawal system of Opus and cycle withdrawal authorizations between multiple accounts to always retain one that can immediately withdraw at any given point in time. As a provision will not reset those requests, the account whose withdrawal authorization is valid at a point a lucrative absorption occurs can be exploited to acquire a bigger share of the collateral.

I believe a medium-risk grade is better suited for this finding as only the "reward" distribution is manipulated and it requires extensive money-translated effort (i.e. gas for maintaining positions active) that will further reduce the economic viability of this exploit.

c4-judge commented 8 months ago

alex-ppg changed the severity to 2 (Med Risk)

c4-judge commented 8 months ago

alex-ppg marked the issue as satisfactory

c4-judge commented 8 months ago

alex-ppg marked the issue as selected for report

minhquanym commented 8 months ago

Hi @alex-ppg, I would like to highlight that this finding shows a unique way to exploit the withdrawal queue using multiple accounts. The other mentioned reports are only able to bypass the time lock for a short period of time, while this report shows that it could be bypassed indefinitely. Thank you for your consideration.

rodiontr commented 8 months ago

Hi @alex-ppg, I would like to highlight that this finding shows a unique way to exploit the withdrawal queue using multiple accounts. The other mentioned reports are only able to bypass the time lock for a short period of time, while this report shows that it could be bypassed indefinitely. Thank you for your consideration.

hi @minhquanym, but the impact is still the same - implementing risk-free yield tactics