Opus - nmirchev8's results

A cross margin credit protocol with autonomous monetary policy and dynamic risk parameters.

General Information

Platform: Code4rena

Start Date: 09/01/2024

Pot Size: $100,000 USDC

Total HM: 13

Participants: 28

Period: 28 days

Judge: 0xsomeone

Total Solo HM: 8

Id: 319

League: ETH

Opus

Findings Distribution

Researcher Performance

Rank: 11/28

Findings: 1

Award: $2,116.86

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: 3docSec

Also found by: etherhood, kfx, nmirchev8

Labels

bug
3 (High Risk)
satisfactory
sufficient quality report
edited-by-warden
duplicate-9

Awards

2116.8629 USDC - $2,116.86

External Links

Lines of code

https://github.com/code-423n4/2024-01-opus/blob/4720e9481a4fb20f4ab4140f9cc391a23ede3817/src/core/shrine.cairo#L1205-L1211 https://github.com/code-423n4/2024-01-opus/blob/4720e9481a4fb20f4ab4140f9cc391a23ede3817/src/core/shrine.cairo#L1046

Vulnerability details

Impact

Shrine has a recovery mode feature, which is activated when the aggregated loan-to-value ratio of all troves in the Shrine is equal to or greater than 70% of the Shrine's threshold Recovery mode adjusted downwards depending on the the extent to which the Shrine's aggregate loan-to-value ratio is greater than the Shrine's recovery mode threshold, down to a floor of 50% of the yang's original threshold. We can see that recoveryMode is considered active dynamically, when a health for a trove is checked, which means that there is a function, which is calculation the weighted average of the thresholds of all yangs, which are supported by the system, amount of all depts and value of all deposited yangs (LTV). And it check whether (value of all dept / value of all yangs) > 70%, and if it is true, threshold for give trove is being scaled by the corresponding value.

if self.is_recovery_mode_helper(shrine_health) { let recovery_mode_threshold: Ray = shrine_health.threshold * RECOVERY_MODE_THRESHOLD_MULTIPLIER.into(); return max( threshold * THRESHOLD_DECREASE_FACTOR.into() * (recovery_mode_threshold / shrine_health.ltv), (threshold.val / 2_u128).into() ); }

As the system is cross-margin and we expect different yangs with different thresholds, this means that average threshold depends on deposited amount of each yang and the corresponding dept minted agains it (it LTV value). This means that if we have yangs for stablecoins, which threshold would be larger (~90%), this could significantly change the average threshold) and so -> LTV.

  • If a user manages to deposit large amount of the yang with largest threshold, mint all dept possible, this will influence the recovery mode calculations and can benefit from liquidating users, when the threshold for their troves is scaled
  • Attacker can use multiple flashloans to influence the overall threshold, liquidate the users, withdraw and repay his flashloans
  • The recovery is "activated", but due to manupulation bounded in the current transaction, which result in:
    • attacker always being first to liquidate a user
    • falsy user liquidations with larger penalty and collateral

Here is the formula, which is calculating weighted average of the thresholds: (yangADeposited / totalDeposited) * yangA% + (yangBDeposited / totalDeposited) * yangBDeposited% = weighted average of the thresholds % (Note that this is for only two yangs and it can go on for as many collateral assets there are) and the total LTV is calculated as follows: allTrovesDept/allDepositedYangsValue

  • The vulnerability has been discussed with sponsors and has been confirmed as a valid attack vector:

<a href="https://imgur.com/9ETzX5i"><img src="https://i.imgur.com/9ETzX5i.png" title="source: imgur.com" /></a>

Proof of Concept

Lets take a look at an example values, which are real for production enviroment:

  • Yang with threshold of 70% and current LTV 65% (minted yin = 3.25M ;deposited collateral = 5M)

  • Yang with threshold of 60% and current LTV 55% (minted yin = 2.75M; deposited collateral = 5M)

  • Yang with threshold of 90% (suppose a stablecoin) (18M minted)

  1. Malicious actor sees that he can benefit from this exploit by liquidating all users, which LTV is x% below the threshold
  2. He uses a flashloan of 20M from the stablecoin -> deposit all and mint max possible amount of yin (90% of 20M)
  3. Lets now calculate weighted average of the thresholds and LTV:
  • (5M / 30M) * 70% + (5M / 30M) * 60% + (20M / 30M) * 90% = 81% , so the manipulation has raised the threshold from avg of 65% -> 81% (16%)
  • And average LTV = (2.75M + 3,25M + 18M) / 30M = 80% (10% > recovery mode threshold)
  1. Exploiter is able to liquidate multiple users, which has been ~ 5% below the liquidation threshold, because their threshold for the operation is scaled by the recovery factor
  2. Exploiter uses his minted yin to liquidate part of their positions. With the yild he made, he can repay his yin dept (18M), withdraw flashloaned assets and repay them.
  3. He has successfully manipulated the system to think that those trove were liquidatable, when they were not

Tools Used

Manual Review

  • Think of a way to obtain the recovery mode from the last block, which will remove the possibility of flashloan manipulations

Assessed type

Context

#0 - tserg

2024-02-07T09:58:38Z

This is valid - duplicate of #205.

#1 - c4-pre-sort

2024-02-10T09:01:04Z

bytes032 marked the issue as sufficient quality report

#2 - c4-pre-sort

2024-02-10T09:01:17Z

bytes032 marked the issue as duplicate of #205

#3 - c4-judge

2024-02-26T16:45:39Z

alex-ppg marked the issue as satisfactory

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter