Open sherlock-admin4 opened 6 months ago
2 comment(s) were left on this issue during the judging contest.
santipu_ commented:
Medium
takarez commented:
seem to be a dupp of 125 due to large deposit and the recommendation also; high(4)
Confirmed, valid! Thank you for reporting this issue!
If an attacker intentionally open position to make the Oracle Maker imbalanced and close position on SpotHedge maker. The cost of this action is the maker swap fees (we'll have swap fees in later update).
We expect there'll be two kinds arbitrageurs come in to help balance Oracle Maker's position.
The slippage of Oracle Maker becomes a positive premium when helping balance Oracle Maker, so arbitrageurs can open reverse position on SpotHedge maker and close on Oracle Maker and earn the premium right away.
Arbitrageurs who're willing to earn funding fees can take over Oracle Maker's position and hedge the position else where, while receiving the funding fee.
In my opinion, this one is a medium and we might not fix it in the near future.
Escalate This should be a high according to Sherlock's definitions: Definite loss of funds without (extensive) limitations of external conditions. Inflicts serious non-material losses (doesn't include contract simply not working).
Since no explanation was given to why this got demoted to medium I'll assume this was following the sponsor's comments, which I'll address here:
The POC clearly demonstrates:
A. a substantial financial loss (see POC output).
B. Without excessive reliance on external conditions.
Escalate This should be a high according to Sherlock's definitions: Definite loss of funds without (extensive) limitations of external conditions. Inflicts serious non-material losses (doesn't include contract simply not working).
Since no explanation was given to why this got demoted to medium I'll assume this was following the sponsor's comments, which I'll address here:
- The sponsor mentioned maker swap fees that will be added in a later update and contribute to the cost of the attack, however these were not mentioned in the contest readme nor in the code and therefore should not affect severity but rather be considered a possible remediation method.
- The sponsor also mentions two types of arbitrageurs that are expected to balance the Oracle Maker's position, however arbitrageurs are irrelevant to this exploit because the attack is conducted within two consecutive blocks (first part block X, second part - block X+1). Since Optimism's mempool is private the attacker is the only one with pre-knowledge of phase 1, and can easily avoid being frontrun on block X+1.
- Regarding "The slippage of Oracle Maker becomes a positive premium when helping balance Oracle Maker" I believe this is inaccurate: When helping balance the Oracle Maker it gives exactly the Oracle price. Opening a reverse position on SpotHedge maker and closing on Oracle Maker involves some loss because of the SpotHedge maker price slippage (slightly worse than the oracle price due to Uniswap slippage/fees).
The POC clearly demonstrates:
A. a substantial financial loss (see POC output).
B. Without excessive reliance on external conditions.
You've created a valid escalation!
To remove the escalation from consideration: Delete your comment.
You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.
If this one is High, then so is https://github.com/sherlock-audit/2024-02-perpetual-judging/issues/126 , because they both are the pattern X Fee Rate is calculated based only on the Y Maker's skew but applied across the entire market, which enables an attacker to generate an extreme X rate for a low cost and leverage that to their benefit
, where X is either Funding or Borrowing and Y is either Oracle or SpotHedge
I think I agree with @nirohgo and high severity here, subsequent update to fees shouldn't be considered if not make known initially.
@nevillehuang You may want to consider the risks from this comment.
@nevillehuang the ability to attack the protocol depends on the values that the admin sets in the configuration. As I point out here, the attack can no longer be performed when the funding fee rate is reduced. I believe this prevents the severity from being High, since admins are trusted to use the right values for their protocol, or else they could just choose ones that 'happen' to cause an exploit, where Sherlock would be on the hook for it. It may even be Low if nirohgo can't show that it can be exploited regardless of the value that the admin sets.
I believe this issue should indeed be high. I see that with not all values the attack is possible, but since the values were taken from other tests by the team, therefore, I think it's safe to assume that these values are intended and default. Hence, as of now, planning to accept the escalation and update the severity to high.
@paco0x there is only a single setting of the values for the parameters. Can you let us know what sort of ranges you expect for the funding parameters, so we can see how much this issue is affected by the expected values? The desmos calculator the docs links to has some ranges - are they representative?
@paco0x there is only a single setting of the values for the parameters. Can you let us know what sort of ranges you expect for the funding parameters, so we can see how much this issue is affected by the expected values? The desmos calculator the docs links to has some ranges - are they representative?
Considering the potential issues, we'll not enable funding fee in our first version in production.
The approximate range of funding rate to begin with can be between 100% and 500% per year under max imbalance ratio. An example config can be:
FundingConfig {
fundingFactor: 200% / 86400 (200% per year under max imbalance ratio)
fundingExponentFactor: 1
}
@WangSecurity according to the above, the expected exponent is 1.0, but the test is using 1.3, which is an extreme value. When the test is changed to use 1.0, the attacker no longer shows a profit and instead shows a loss (even with changing the uniswap fee down to 0.05%). Since it's conditional on the admin choosing an extreme value, I don't think this finding can be a High. I believe the rules about admin-controlled values being an admin error and thus invalid, are in place so that people doing the judging contest can correctly decide severity without having to ask the sponsor for the expected values.
@WangSecurity I discussed possible values of these configs with @42bchen during the contest, his answer was that they don't yet know what production values are going to be (which makes sense as they need to be effective to incentivize the right behavior). Given that, their final values can only be known in production, and limiting them in order to avoid an exploit (even if done as a workaround) should not take away from the finding severity.
On another matter (@Evert0x ), is it within Sherlock rules for a watson to "escalate" a finding, post the escalation period? (and without risking their escalation ratio)? seems somewhat unfair.
The finding was escalated by the submitter in order to raise the severity, and I'm trying to show why it should not be. I don't see how pointing out the usual rules is an unfair argument as to why it should not be a High
@nirohgo can you provide a screenshot or a link to these messages, just so I can be sure, still deciding on the severity and validity here and will provide my decision tomorrow. Thanks to both of watsons for being active on providing additional info
I disagree that the administrator can prevent the exploitation of this vulnerability. That's why when I submitted my report, I chose High severity. The assertion that changing the exponent from 1.3 to 1.0 will make the exploit impossible is true only for the proof of concept shown in this report, but not as a whole. LP can influence the total amount of deposits, and by exploiting this, an attacker can make a profit. It is not mandatory for the position to be closed in the next block; it could be in the one after that, for example. A combined attack is possible by opening a position and changing the total deposited amount. There are many attack scenarios, but there are no limiting factors that make it impossible. Exploiting this vulnerability boils down to risk management in order to choose the right approach for the respective state of the protocol. I tried to explain this in my report, but my choice to show a different attack path from the obvious one led to the escalation of my report. I've said it before, but in my opinion, it cannot be expected that all possible ways to exploit a vulnerability will be presented in one report; it is not practical.
I think medium severity is appropriate here. The attack is indeed profitable with 1.3e18, but unprofitable with 1.0e18. It's also profitable with 1.2e18, but unprofitable with 1.1e18. I see that the sponsor says the approximate funding exponent will be indeed 1. But, as we see from nirohgo point, he asked about it during the contest and the sponsor answered they don't know yet. Moreover, I don't the rule that the admin should always set the correct value can be applied here, cause (as I understand) setting the exponent to 1.2e18+ doesn't disrupt the work of the protocol, but opens a window for the attack. Hence, I see at as a valid attack with certain constraints and state to be executed profitably.
Hence, I'm planning to reject the escalation and leave the issue as it is.
@WangSecurity according to sherlock rules and definitions this should be a high. Your reasoning for medium rely on 1. a "counter escalation" that was made against sherlock rules (after escalation period was over) 2. against the information that was provided during the contest (the test config values plus communication that more precise values are not yet known) and therefore lower on Sherlock's hierarchy of truth.
I'm judging it accroding to rules for Medium Severity:
Causes a loss of funds but requires certain external conditions or specific states, or a loss is highly constrained.
My decision remains the same: reject the escalation and leave the issue as it is.
@WangSecurity every finding requires some conditions or specific states. (for example #123, which was accepted as High, requires that there be two offline Pyth price updates that were not reported onchain yet at that the price diff between them enables the attack). My point in the case of this finding is that (given the information available during the audit - that production configs are not known and only provided estimate is the one in the tests) is there is no reason to believe 1.1e18 or 1.0e18 are more likely than 1.3e18 or 1.2e18. Therefore I do not believe that specific handpicked exponent values where the attack does not work should count as a strong enough dependency on certain external conditions or specific states to make this a medium. Also, the severity of loss (as displayed in the POC) should also be taken into account here when determining the severity. (from my experience many accepted high's on sherlock may not work given specific config settings, and yet still count as high because they will occur with reasonably set configs and cause significant loss).
@nirohgo I see your points and I'm open to discussing them, but before that I would like to get a small clarification from your side. In issue #116 you say that setting "the OM max spread to a larger value than the price band setting", i.e. admin setting the values that open a window for the vulnerability is an admin error. But in that case admin setting the values that open a window for the vulnerability is not an admin error. I understand it's two completely different issues, but I believe in both cases the trusted admin rule should be applied correctly. What do you think about it?
@WangSecurity Perhaps my question is naive, but what is the intuition behind the statement that the attack is not profitable with 1.0e18? I examined nirohgo's proof of concept in more detail, and in my opinion, the problem with it is that there is not enough liquidity in the corresponding range, leading to significant slippage. I added liquidity to the respective range, and the attack became profitable. I reduced the fee from 0.3 to 0.05 to show a greater profit, but with 0.3, smaller profits are also possible.
Logs:
Exploiter Quote balance at Start: 5000000000000
Funding Fee Rate after short:
-4999999999999999
Exploiter Quote balance at End: 5016509239587
You deposited $5M and reduced the tick range from 1774440 ticks to only 20 ticks. I don't think that's likely to happen either
@nirohgo I see your points and I'm open to discussing them, but before that I would like to get a small clarification from your side. In issue #116 you say that setting "the OM max spread to a larger value than the price band setting", i.e. admin setting the values that open a window for the vulnerability is an admin error. But in that case admin setting the values that open a window for the vulnerability is not an admin error. I understand it's two completely different issues, but I believe in both cases the trusted admin rule should be applied correctly. What do you think about it?
@WangSecurity #116 depends on admins setting a specific boundary (max OM spread) to a value higher then the overriding general boundary (price band). This is a clear admin error even without the finding or liquidations (whenever the OM price exceeds the price band transactions will fail). In this case there is no logical error is setting the exponent config to a specific value, the exponent needs to create a curve that's efficient enough to incentivize the market to reduce risk. As the team specified during the contest the exact value is unknown (the best initial guess was the test value).
First, the attack depends on the actions of a TRUSTED admin (setting funding exponent). Other external factors, like the liquidity and ticks, are also required for a successful attack. That's why I believe Medium is appropriate for this report.
Planning to reject the escalation and leave the issue as it is.
These are not external factors because the attacker can control them. Do you agree that 1) and 2) are possible ? If so this would mean that the attack doesn't depend on trusted admin action because the attack would be profitable for all 1.0e18, 1.1e18, 1.2e18 and 1.3e18.
depositing liquidity and having yourself trade against it, without you also pushing the price back in your favor before withdrawing it, will result in impermanent loss, which is a cost that you yourself will have to pay back
The exploiter would deposit within the current price range, which already has significant liquidity. Therefore, the deposit wouldn't be as large. The exploiter wouldn't withdraw immediately after the attack but would wait a sufficient amount of time before doing so in order to recover the losses. Even if the profit and losses from the attack are equal for the attacker, it still results in a loss for the maker and is thus a valid attack with no additional constraints. Please correct me if I am wrong.
Also what do you think about 2) ?
Assumes the price will move back in your favor, and that someone 'pays you back' for the amount you pushed it. For 2, you'd have to show a valid poc, and I suspect that nirohgo didn't go along with your initial suggestion, because there's some confounding factor.
If you're planning on providing a poc, please make sure it works will all values that the admin can set, so we can avoid extra endless discussions about whether the value is valid or not
@IllIllI000 I can prepare a new POC if it is needed but should know what more is expected from the new POC. In my previous POC, I showed that the attack is profitable even if the exponent is 1.0e18. The same POC works for 1.1e18, 1.2e18 as well. Your consideration was that the range is too small for such large liquidity but this was just for simplicity. If you look into the test pool, you will see that the initial liquidity is only 100 base tokens and 2,000,000 collateral tokens for the range [-887,220, 887,220]. For comparison, in the USDC/ETH pool on Uniswap, there is >200 million TVL and at each of the ticks around the active one, there are around 300,000 liquidity. Should I simulate something like this?
Assumes the price will move back in your favor, and that someone 'pays you back' for the amount you pushed it. For 2, you'd have to show a valid poc, and I suspect that nirohgo didn't go along with your https://github.com/sherlock-audit/2024-02-perpetual-judging/issues/133#issuecomment-2074641984 suggestion, because there's some confounding factor.
I think that the market will restore the real price in the pool. Moreover the fees will also help to recover the losses. I already mentioned that the important thing here is to have losses for the maker in order to have an attack. Equal losses/profits for the attacker or even a small loss is not a problem. However i believe that the attack is profitable for the exploiter too.
If nirohgo thinks that the adjustment that i made to the POC is not correct is free to comment.
@WangSecurity What do you think ?
Hi @gstoyanovbg if you look through the escalations that I have commented on, you'll see that I've spent many hours countering claims, over multiple days, for uncertain benefit. I hope you'll understand if I don't continue this here by thinking of all the possible scenarios, and laying out a poc framework for you, solely for my detriment. What I'll say about your specific point is that nirohgo's POC used a wide tick range in order to simulate a normal market, where the attacker didn't have to introduce special externalities in order to use the uniswap pool. By adding extra liquidity and a specific tick range, you are adding an externality that has to be accounted for. You need to not do that. I believe you'd need to show that the admin parameters have zero effect on whether or not a profit can be made, over normal uniswap/market scenarios that happen very frequently in order for this to become a high.
I don't think that the range from the nirohgo's POC is a good example for a normal Uniswap V3 pool. The main idea of Uniswap V3 is to concentrate liquidity in a specific range. Logically, the primary available liquidity is concentrated around the current price. To avoid making unfounded claims, I will use the USDC/ETH (0.05) pool on Uniswap V3 as an example which has 200m TVL.
From the graph, you can see how liquidity is distributed, with it being insignificant at the left end - around 30k per tick. The range of prices is [2565, 3827]. The price at the moment is 3133. The percentage difference between the current price and that at the left end of the range is about 22%. Similarly for the right boundary, the percentage is the same. I attempted to simulate something like this in the new POC. The numbers are as follows:
In my opinion, this scenario is realistic enough, even more unfavorable than reality due to the even distribution of liquidity. The results are as follows:
1.0e18:
Exploiter Quote balance at Start: 5000000000000
Funding Fee Rate after short: -4999999999999999
Exploiter Quote balance at End: 5013664397043
1.1e18
Exploiter Quote balance at Start: 5000000000000
Funding Fee Rate after short: -21334035032232417
Exploiter Quote balance at End: 5078754700088
1.2e18
Exploiter Quote balance at Start: 5000000000000
Funding Fee Rate after short: -91028210151304013
Exploiter Quote balance at End: 5356482461172
I'm not a uniswap expert. Please do the actual add/remove liquidity in the POC, including it in the start/end balance (both tokens). Also, I didn't check, but I don't think 1e18 is the lower bound of the possible admin-set values
But we also don’t know what the project side’s psychological upper limit is for this value.
@IllIllI000 I don't understand what changes you want to make to this POC and how they will contribute to the discussion, so I'll wait to hear the judge's opinion (@WangSecurity ) before making another POC. I hope you understand that if every participant in this discussion requests a custom POC for their own reasons, I'll have to build POCs for this discussion full-time. That's why I prefer to wait a bit and see if anyone else has any other comments.
Regarding the lower bound of the exponent, the administrator can set it to be 0 or a value close to zero. If we assume that this is an argument, then this discussion could have ended on the third comment and not waste our time. But I believe that here we evaluate realistic values for the exponent, and the sponsor clearly stated in their comment that the value will be 1.0. The whole argumentation so far has been built on the fact that nirohgo's POC does not show profit for this value. I think I explained in detail where the problem with this POC comes from and that if a more realistic simulation is done, there is profit.
Firstly, thanks to all the Watsons providing endless value on this escalation.
Secondly, @gstoyanovbg as I understand, in your scenario, laid out in the last comments, the attack deviates from the original @nirohgo PoC.
If that's correct, then I see two different scenarios. Let's start with the original scenario. There are several values that effect the attack: funding exponent (set by admins), liquidity and price range.
Again thanks to @IllIllI000 @gstoyanovbg and @nirohgo for providing a lot of value here.
@WangSecurity The profitability of the attack from the POC of nirohgo depends on the funding exponent and the available liquidity in the respective price range. If a too large position is opened, but there is not enough liquidity in the corresponding price range, part of the value is lost due to excessive slippage. My initial idea was that the attacker could add liquidity where it is lacking in order to extract value from the maker. Or simply calculate the position size to be proportional to the available liquidity so that there is not a large slippage. However, when I started to build the POC, I noticed that in the USDC/ETH pool on Uniswap V3 there is enough liquidity so that nirohgo's original POC is profitable for funding exponent values >= 1.0e18. Therefore, in my latest POC, I decided to simply mimic a pool with liquidity similar to that in USDC/ETH to prove my claim. I still believe that the attacker can add liquidity if necessary and that it can be profitable, it just turned out that it was not necessary in this case.
To summarize, in my opinion, the exploiter can extract value from the maker for any realistic value of the funding exponent, i.e., >=1.0e18. In most cases, I expect the available liquidity in Uniswap to be sufficient; if not, the attack can be modified to add additional liquidity from the attacker. Earlier in the discussion, we discussed how to proceed in this scenario. I have not analyzed values of the funding exponent < 1.0e18, but I expect that for small values of the funding exponent, the attack will not be profitable. However, I do not think such values represent a realistic scenario. The sponsor has already clearly stated that they intend to use a value of 1.0e18 for the funding exponent. In the tests, the value was 1.3e18. It is also debatable whether there is a theoretical sense in low values of the funding exponent because the incentive for users would be too small
Since the attack can be executed on any funding exponent value discussed above (1.0e18 - 1.3e18), then the liquidity at specific price range is a bigger constraint on the attack profit. But it can be controlled by the attacker as they themselves can add liquidity at a specific price, correct? @gstoyanovbg
@WangSecurity Correct.
First, the attack can be executed independently on the funding exponent set by the admin (assuming they values are realistic). Even though the possibility and profitable depend on certain liquidity conditions. I believe these conditions are very realistic to occur. Hence, high severity is appropriate here:
Definite loss of funds without (extensive) limitations of external conditions
Planning to accept the escalation and upgrade severity to High
For full transparency: https://discord.com/channels/812037309376495636/1013592891773419520/1234858790516690966
@gstoyanovbg your PoC relies on a lot more liquidity than there currently is, and therefore your PoC needs to model the costs of adding and removing the liquidity:
https://info.uniswap.org/#/optimism/pools/0x1fb3cf6e48f1e7b10213e7b6d87d4c073c7fdb7b
[...] isn't USDC/ETH pool TVL on Optimism just 4M?
https://discord.com/channels/812037309376495636/1013592891773419520/1234878162697977986
Further, if you're adding liquidity for two blocks, you can't use a flash loan and you're at risk of the price moving, or someone taking your liquidity, so I don't think this can be High at the moment. For your argument that you can still attack but smaller amounts with the given liquidity, can you quantify how much an attack can gain given the 4M liquidity is spread over the whole pool, not just the current price, and show that the attacker can gain more than dust amounts with the 1e18 value?
@IllIllI000 First, thanks to you and your lawyers for noticing that the TVL of the mentioned pool is 4M on Optimism. The graph I attached is from the same pool but on Ethereum. It has been a while since the end of the contest, and at that moment, I did not realize that Ethereum is not on the list of supported chains. I apologize for the mistake.
However, I don't think there is a significant difference, and I will soon upload a new POC to clear up any doubts.
As the mentioned "lawyer", having read the discussion and I really don't understand where we are even trying to head towards.
Let's first be clear here that I don't care about any bounties, and any "lawyers" who are aiming for the bounty can try and push this issue to their favored direction. The only direction I am respecting is where the truth is headed, hence this analysis.
What is clear from just the issue, and has been reiterated/implied multiple times throughout the discussion, is that the "attack" is possible regardless. From the formula, it is clear that the funding rate is proportional to the OM's open notional, which is exactly what this attack is trying to achieve.
Then the profitability depends on multiple factors:
Then the questions to be analyzed here are:
Now, is this big picture big enough to look at? Have we narrowed it down enough for a numerical analysis?
Edit: Re-analyzed the formula and it looks like non-basepool traders do not have a dampening effect. So that's one thing out of the way.
I'll make just this comment and not engage in this discussion.
@gstoyanovbg wanted to ask how's the PoC going and how much time approximately you need?
@WangSecurity Tomorrow will post it. Sorry for the delay i was very busy last couple of days.
@WangSecurity I'm ready with the new POC, and it includes several improvements compared to the previous ones. To avoid doubts about the way I simulate the Uniswap pool, I changed the contracts to use the actual Uniswap V3 WETH/USDC 0.05% pool on Optimism via a fork from a specific block. The block is a random block from yesterday. I've prepared 2 tests. In one, only the available liquidity in the pool is used, and in the other, I show how adding additional liquidity can increase profits without any losses. I also noticed another mistake in the previous POCs - when positions are closed and the amount is withdrawn, it turns out that there isn't always enough collateral to withdraw the entire profit. In the current POC, I corrected this by simulating a loss from another trader so that the entire profit can be withdrawn. The changes span across several files, and I'm attaching all of them. If anyone encounters issues with running this, they can contact me.
Results:
From the PoC (both the recently provided PoC, the PoC on the submission, and the sponsor's test file):
config.setFundingConfig(marketId, 0.005e18, 1.0e18, address(oracle_maker));
Aside from the funding exponent, there is also the funding rate (check function signature), and it's currently being set at a very unrealistic value. Here's why.
Although it's not known before the contest, the sponsor stated here that the intended funding rate (not exponent) is 100% to 500% a year. The given config (on the sponsor's comment) also looks weird, because 86400 is the number of seconds in a day, not in a year (for a year, it's 31536000 seconds).
Let's just say it's 500% a day, then $5/86400 \approx 6 10^{-5}$ per second. Then the funding rate in the PoC being $100$ times higher than intended (and if being 500% a year, then it's $36500$ times higher than intended). A funding rate of 100% a day means, at 1.0 exponent and max utilization, you pay a fee worth 100% of your position per day*. How is a fee of 5 times higher than this realistic?
For a reference of what a "realistic" value is, Binance Futures's funding rate are mostly 0.01% for most assets, and the funding interval is 8 hours. That means one side pays the other 0.01% worth of their position every 8 hours. Divided by the number of seconds in 8 hours, this gives a funding rate of $3.47 10^{-7}$% (or $3.47 10^{-9}$) per second, even if they technically don't pay this fee that often.
Back to the main issue, a funding rate of 500% per year (as per the sponsor's comment) is $5/(36586400) = 1.6 10^{-7}$. Then a funding rate of 0.005e18
or $5 * 10^{-3}$ per second is at least $30000$ times higher than the sponsor's stated upper bound of value. Let us also note that this value is only achievable on the maximum utilization (smaller utilizations scale down proportionally), and that 500% is the upper bound on the sponsor's stated value, not the realistic intended value.
Then any given profit from the funding fee has to be divided by $30000$, and the loss (from swaps, network fee, spread, etc) stays the same.
To sum up, because the funding rate is by second, and not anything else, the correct funding config for a 1.0 exponent and 500% funding rate per year should be:
config.setFundingConfig(marketId, 0.00000016e18, 1.0e18, address(oracle_maker)); // 5e18 divided by the number of seconds in a year
And the attack is no longer profitable, even on the upper bound of the sponsor's stated funding rate.
Because the attack is no longer profitable, and the fee per second is so small (comparable to that of the interest rate of a standard lending protocol), and also because the attacker carries a significant risk of holding a large position for a minimal fee profit, I will also go the distance and am arguing this to be a Low.
nirohgo
high
Funding Fee Rate is calculated based only on the Oracle Maker's skew but applied across the entire market, which enables an attacker to generate an extreme funding rate for a low cost and leverage that to their benefit
Summary
The fact that the Funding Fee rate is calculated only based on the Oracle Maker's position skew enables an exploiter to open a large long position on the Oracle Maker that generates an extreme funding fee paid by long takers, and then close the position (+open an opposite one) on the SpotHedge maker within the same block while maintaining the funding fee value and direction. This can be used to generate various attacks as detailed below.
Vulnerability Detail
Perpetual uses funding fee to balance between long and short positions, mainly to balance/reduce exposure of the Oracle Maker (from the docs: "In our system, having a funding fee will be beneficial for the Oracle Pool". Presumably for this reason the funding rate is calculated based only on the Oracle Maker's position skew as can be seen in this code snippet taken from the getCurrentFundingRate function (note that basePool is neccesarily the Oracle Maker since it is type-casted to OracleMaker in the code):
However, the funding fee applies to any position in the market (as can be seen in the Vault::settlePosition function) which enables an exploiter to create a very high funding rate for a low cost by opening a large long position on the oracle maker and close the position immediately after on the HSBM maker (possibly also opening a short depending on the type of attack). Since the opposite position does not affect the funding rate (as it is settled with the SpotHedge maker), the funding rate will maintain its extreme value and its direction.
This maneuver can generate multiple types of attacks that can be conducted individually or combined:
A. Griefing/Liquidation attack - The attacker creates an extreme funding rate that causes immediate loss to position holders of the attacked direction, possibly making many positions liquidatable on the next block. This attack is conducted as follows:
A.1. Attacker opens a maximal long position on the oracle maker creating an extremely high funding rate paid by longs. A.2. Attacker closes their long position using the HSBM maker. This means the extreme high funding rate is unaffected since its calculated based on the oracle maker only. (A1 and A2 can be done in an atomic transaction from an attacker contract).
A.3. Starting from the next block any long position in the system incures a very high cost per block, likely making many positions liquidatable immediately.
A.4. The cost for the attacker is only the negative PnL caused by the spread between the oracle and HSBM makers. The attacker can offset the cost and make a profit by running a transaction at the start of the next block that liquidates all positions that were liquidated by the move (the attacker has information advantage over other liquidators and are likely to win the liquidations).
B. Profiting from large funding fee within one block by also opening a short (exfiltrating funds from the PnL pool).
B.1. the attack starts similarly to A: the attacker opens a maximal long position on the OM and then a counter short position on the HSBM maker, only this time the attacker also opens a short on the SpotHedge maker that gains the attacker funding fees starting from the next block.
B.2. The attacker can close the short position at the start of the next block to reduce risk, taking profit from the fee paid for the one block, in addition to liquidating any affected positions as in scenario A.
B.3. The cost of attack: negative PnL caused by spread between the two makers, plus borrowing fee. However because borrowing fee does not grow exponentially with utilization rate like the funding fee, it is covered by the funding fee with a profit.
C. Profiting from a large deposit to the oracle maker/withdraw within one block.
C.1. The attack runs the same as scenario A, only the attacker also makes a large deposit to the oracle maker, and withdraws on the next block.
C.2. Since share values take into account pending fees, the share value will increase significantly from one block to the next because the oracle maker will also get a high funding fee within that one block (this is because oracle maker also holds a large short position as a result of the attackers initial postion, that gets paid funding fee). Note that in this scenarion the attacker needs to verify that there is no expected loss to share value between these two blocks
The POC below shows how with reasonable market considitions the attacker can make a significant profit, specifically using only attack type B.
POC
The following POC shows the scenario where the attacker generates a high funding rate paid by longs, while opening a large short position for themselves, then on the next block the attacker closes the short with a significant gain from funding fee (while the HSBM maker pays the funding fee)
To run:
A. create a test.sol file under the perp-contract-v3/test/spotHedgeMaker/ folder and add the code below to it. B. Run forge test --match-test testFundingFeePOC -vv
Impact
The various possible attacks detailed above generate immediate profits to the exploiter that can be withdrawn immediately if enough PnL exists in the pool, diluting the PnL pool on the expense of users and causing them financial loss from not being able to withdraw their profits. In addition, as detailed above many positions can be made liquidatable following the attack causing further damage.
Code Snippet
https://github.com/sherlock-audit/2024-02-perpetual/blob/02f17e70a23da5d71364268ccf7ed9ee7cedf428/perp-contract-v3/src/fundingFee/FundingFee.sol#L104
Tool used
Manual Review Foundry
Recommendations
To mitigate this issue it is essential to resolve the root cause: the fact that funding fee is set using only a part of the market (Oracle Maker). Instead, the entire market long/short positions should be used to determine the rate. This will prevent an exploiter from opening the counter position (that gains fee) without that position also affecting the funding rate.