sherlock-audit / 2023-12-flatmoney-judging

9 stars 8 forks source link

shaka - Oracle can return different prices in same transaction #216

Open sherlock-admin2 opened 5 months ago

sherlock-admin2 commented 5 months ago

shaka

high

Oracle can return different prices in same transaction

Summary

The Pyth network oracle contract allows to submit and read two different prices in the same transaction. This can be used to create arbitrage opportunities that can make a profit with no risk at the expense of users on the other side of the trade.

Vulnerability Detail

OracleModule.sol uses Pyth network as the primary source of price feeds. This oracle works in the following way:

One thing to note is that the Pyth network is constantly updating the latest price (every 400ms), so when a new price is submitted on-chain it is not necessary that the price is the latest one. Otherwise, the process of querying the data off-chain, building the transaction, and submitting it on-chain would be required to be done with a latency of less than 400ms, which is not feasible. This makes it possible to submit two different prices in the same transaction and, thus, fetch two different prices in the same transaction.

This can be used to create some arbitrage opportunities that can make a profit with no risk.

How this can be exploited

An example of how this can be exploited, and showed in the PoC, would be:

The result is approximately a profit of

adjustmentSize * (secondPrice - firstPrice) - (adjustmentSize * tradeFees * 2)

Note: For simplicity, we do not take into account the initial size of the position, which in any case can be insignificant compared to the adjustment size. The keeper fee is also not included, as is the owner of the position that is executing the orders.

The following things are required to make a profit out of this attack:

In the case of not being able to obtain the required delta or observing that a keeper has already submitted a transaction to execute them before the delta is obtained, the user can simply cancel the limit order and will have just the adjustment order executed.

Another possible strategy would pass through the following steps:

The result in this case is having a position with the same size as the original one, but having either lowered the position.lastPrice or getting a profit from the original position, depending on how the price has moved since the original position was opened.

Proof of concept

Pyth network multiple submissions We can find proof that it is possible to submit and read two different prices in the same transaction [here](https://basescan.org/tx/0x0e0c22e5996ae58bbff806eba6d51e8fc773a3598ef0e0a359432e08f0b51b95). In this transaction `updatePriceFeeds` is called with two different prices. After each call the current price is fetched and an event is emitted with the price and timestamp received. As we can see, the values fetched are different for each query of the price. ```js Address 0x8250f4af4b972684f7b336503e2d6dfedeb1487a Name PriceFeedUpdate (index_topic_1 bytes32 id, uint64 publishTime, int64 price, uint64 conf) Topics 0 0xd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec 1 FF61491A931112DDF1BD8147CD1B641375F79F5825126D665480874634FD0ACE Data publishTime: 1706358779 price: 226646416525 conf: 115941591 Address 0xbf668dadb9cb8934468fcba6103fb42bb50f31ec Topics 0 0x734558db0ee3a7f77fb28b877f9d617525904e6dad1559f727ec93aa06370866 Data 226646416525 1706358779 Address 0x8250f4af4b972684f7b336503e2d6dfedeb1487a Name PriceFeedUpdate (index_topic_1 bytes32 id, uint64 publishTime, int64 price, uint64 conf)View Source Topics 0 0xd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec 1 FF61491A931112DDF1BD8147CD1B641375F79F5825126D665480874634FD0ACE Data publishTime: 1706358790 price: 226649088828 conf: 119840116 Address 0xbf668dadb9cb8934468fcba6103fb42bb50f31ec Topics 0 0x734558db0ee3a7f77fb28b877f9d617525904e6dad1559f727ec93aa06370866 Data 226649088828 1706358790 ```
Arbitrage example Add the following function to the `OracleTest` contract and run `forge test --mt testMultiplePricesInSameTx -vv`: ```solidity function testMultiplePricesInSameTx() public { // Setup vm.startPrank(admin); leverageModProxy.setLevTradingFee(0.001e18); // 0.1% uint256 collateralPrice = 1000e8; setWethPrice(collateralPrice); announceAndExecuteDeposit({ traderAccount: bob, keeperAccount: keeper, depositAmount: 10000e18, oraclePrice: collateralPrice, keeperFeeAmount: 0 }); uint256 aliceCollateralBalanceBefore = WETH.balanceOf(alice); // Create small leverage position uint256 initialMargin = 0.05e18; uint256 initialSize = 0.1e18; uint256 tokenId = announceAndExecuteLeverageOpen({ traderAccount: alice, keeperAccount: keeper, margin: initialMargin, additionalSize: initialSize, oraclePrice: collateralPrice, keeperFeeAmount: 0 }); // Announce leverage adjustment announceAdjustLeverage({ traderAccount: alice, tokenId: tokenId, marginAdjustment: 100e18, additionalSizeAdjustment: 2400e18, keeperFeeAmount: 0 }); // Anounce limit order in the same block vm.startPrank(alice); limitOrderProxy.announceLimitOrder({ tokenId: tokenId, priceLowerThreshold: 0, priceUpperThreshold: 1 // executable at any price }); // Wait for the orders to be executable skip(vaultProxy.minExecutabilityAge()); bytes[] memory priceUpdateData1 = getPriceUpdateData(collateralPrice); // Price increases slightly after one second skip(1); bytes[] memory priceUpdateData2 = getPriceUpdateData(collateralPrice + 1.2e8); // Execute the adjustment with the lower price and the limit order with the higher price delayedOrderProxy.executeOrder{value: 1}(alice, priceUpdateData1); limitOrderProxy.executeLimitOrder{value: 1}(tokenId, priceUpdateData2); uint256 aliceCollateralBalanceAfter = WETH.balanceOf(alice); if (aliceCollateralBalanceAfter < aliceCollateralBalanceBefore) { console2.log("loss: %s", aliceCollateralBalanceBefore - aliceCollateralBalanceAfter); } else { console2.log("profit: %s", aliceCollateralBalanceAfter - aliceCollateralBalanceBefore); } } ``` Console output: ```js [PASS] testMultiplePricesInSameTx() (gas: 2351256) Logs: profit: 475467998401917697 Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 13.67ms ```

Impact

Different oracle prices can be fetched in the same transaction, which can be used to create arbitrage opportunities that can make a profit with no risk at the expense of users on the other side of the trade.

Code Snippet

https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/OracleModule.sol#L69

https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/OracleModule.sol#L167

Tool used

Manual Review

Recommendation

File: OracleModule.sol
    FlatcoinStructs.OffchainOracle public offchainOracle; // Offchain Pyth network oracle

+   uint256 public lastOffchainUpdate;

    (...)

    function updatePythPrice(address sender, bytes[] calldata priceUpdateData) external payable nonReentrant {
+       if (lastOffchainUpdate >= block.timestamp) return;
+       lastOffchainUpdate = block.timestamp;
+
        // Get fee amount to pay to Pyth
        uint256 fee = offchainOracle.oracleContract.getUpdateFee(priceUpdateData);
sherlock-admin commented 5 months ago

1 comment(s) were left on this issue during the judging contest.

takarez commented:

invalid

sherlock-admin commented 5 months ago

The protocol team fixed this issue in PR/commit https://github.com/dhedge/flatcoin-v1/pull/276.

0xLogos commented 5 months ago

Escalate

Low (at least medium)

sherlock-admin2 commented 5 months ago

Escalate

Low (at least medium)

  • trader fee should be small
  • volatility should be high
  • profit is small and not guaranteed, loss is possible
  • can do roughly the same executing 2 last steps in 2 consecutive txs

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.

shaka0x commented 5 months ago
  • trader fee should be small

The PoC uses the trade fees mentioned in the documentation and in the test suite. We can argue that it can be increase, but by the same token it can also be decreased and make the attack even more profitable.

  • volatility should be high

A change of 0.1% is enough.

  • profit is small and not guaranteed, loss is possible

As I stated, the user can just cancel the limit order if it is not favorable, so no loss beyond the gas fees of the txs.

  • can do roughly the same executing 2 last steps in 2 consecutive txs

The attacker has no control over the change in the prices submitted between two transactions. Doing it atomically is the only way he can assured that the second is greater than the first or vice versa.

0xLogos commented 5 months ago

@shaka0x

hmm, i see...

Attack easily can fail:

xiaoming9090 commented 5 months ago

Escalate.

The risk rating of this issue should be Medium.

The only token in scope for this audit contest is rETH per the Contest's README. Thus, we will use rETH for the rest of the example.

Also, in the setup script, the minExecutabilityAge is set to 10 seconds and maxExecutabilityAge is set to 1 minute. The system will only accept the Pyth price that is generated within the time between T1 and T2 (in Green below), which is within the 1-minute range.

image

For the attack to be profitable, the following equation needs to be satisfied (ignoring the gas fee for simplicity - but the attack will be slightly more difficult if we consider the gas fee. So we are being optimistic below)

Original Formula:
adjustmentSize * (secondPrice - firstPrice) - (adjustmentSize * tradeFees * 2) > 0

For it to break even against the trade fee
(secondPrice - firstPrice) > tradeFees * 2
(secondPrice - firstPrice) > 0.1% * 2
(secondPrice - firstPrice) > 0.2%

The first requirement for the attack to break even (gain of zero or more) is that the ETH increases by more than 0.2% within 1 minute (e.g., \$3000 to above \$3006), which might or might not happen. Note that ETH is generally not a volatile asset. My calculation shows that the price increase needs to be more than 0.2% to break even.

image

The second requirement is that while the malicious keeper is waiting for the right ETH price increase within the 1-minute timeframe if any other keeper executes EITHER the adjustment order OR limit close order, the attack path will be broken. The malicious keeper has to restart again. In addition, the malicious keeper will lose their trading fee when their malicious orders are being executed by someone else because a trade fee needs to be paid whenever an order is executed. Thus, this attack is generally unprofitable due to the high risk of failure, and when failure occurs, the malicious keeper needs to pay or lose the trade fee (no refund).

The report also mentioned the following, which could allow malicious keepers to cancel the limit order to mitigate the risk of loss. However, the problem is that the protocol is intended to be deployed on Base only (Per Contest's Readme), which is similar to Optimism L2 that uses a sequencer. The sequencer operates in the FIFO (first in first out) manner with a queuing system. Thus, by the time the malicious keeper is aware of the unfavorable condition or some other keeper intends to execute their orders, it is already too late as the malicious keeper cannot front-run someone else TX due to the Sequence's queuing design. Even on Ethereum, there is no guarantee that one can always front-run a TX unless one pays an enormous amount of gas fee.

In the case of not being able to obtain the required delta or observing that a keeper has already submitted a transaction to execute them before the delta is obtained, the user can simply cancel the limit order and will have just the adjustment order executed.

Lastly, the adjustment size of the position must be large enough to overcome the risk VS profit hurdle. My above chart shows that 10 ETH will give around 30 USD profit if the price increases by more than 0.02%, and 100 ETH will give around 300 USD profit if the attack is successful.

The protocol is designed in a manner where it is balanced most of the time (delta-neutral), using various incentives to bring the balance back. This means most of the time, the short (LPs) and long trader sides will be 100%-100%, respectively. The worst case it can go is 100%-120% as the system will prevent the skew to be more than 20%. Thus, there is a limit being imposed on the position size that a user can open. If the LP side is 100 ETH, and the current total long position size is 115 ETH. The maximum amount of position size one can open is left with 5 ETH. This is another constraint that the attacker faces.

sherlock-admin2 commented 5 months ago

Escalate.

The risk rating of this issue should be Medium.

The only token in scope for this audit contest is rETH per the Contest's README. Thus, we will use rETH for the rest of the example.

Also, in the setup script, the minExecutabilityAge is set to 10 seconds and maxExecutabilityAge is set to 1 minute. The system will only accept the Pyth price that is generated within the time between T1 and T2 (in Green below), which is within the 1-minute range.

image

For the attack to be profitable, the following equation needs to be satisfied (ignoring the gas fee for simplicity - but the attack will be slightly more difficult if we consider the gas fee. So we are being optimistic below)

Original Formula:
adjustmentSize * (secondPrice - firstPrice) - (adjustmentSize * tradeFees * 2) > 0

For it to break even against the trade fee
(secondPrice - firstPrice) > tradeFees * 2
(secondPrice - firstPrice) > 0.1% * 2
(secondPrice - firstPrice) > 0.2%

The first requirement for the attack to break even (gain of zero or more) is that the ETH increases by more than 0.2% within 1 minute (e.g., \$3000 to above \$3006), which might or might not happen. Note that ETH is generally not a volatile asset. My calculation shows that the price increase needs to be more than 0.2% to break even.

image

The second requirement is that while the malicious keeper is waiting for the right ETH price increase within the 1-minute timeframe if any other keeper executes EITHER the adjustment order OR limit close order, the attack path will be broken. The malicious keeper has to restart again. In addition, the malicious keeper will lose their trading fee when their malicious orders are being executed by someone else because a trade fee needs to be paid whenever an order is executed. Thus, this attack is generally unprofitable due to the high risk of failure, and when failure occurs, the malicious keeper needs to pay or lose the trade fee (no refund).

The report also mentioned the following, which could allow malicious keepers to cancel the limit order to mitigate the risk of loss. However, the problem is that the protocol is intended to be deployed on Base only (Per Contest's Readme), which is similar to Optimism L2 that uses a sequencer. The sequencer operates in the FIFO (first in first out) manner with a queuing system. Thus, by the time the malicious keeper is aware of the unfavorable condition or some other keeper intends to execute their orders, it is already too late as the malicious keeper cannot front-run someone else TX due to the Sequence's queuing design. Even on Ethereum, there is no guarantee that one can always front-run a TX unless one pays an enormous amount of gas fee.

In the case of not being able to obtain the required delta or observing that a keeper has already submitted a transaction to execute them before the delta is obtained, the user can simply cancel the limit order and will have just the adjustment order executed.

Lastly, the adjustment size of the position must be large enough to overcome the risk VS profit hurdle. My above chart shows that 10 ETH will give around 30 USD profit if the price increases by more than 0.02%, and 100 ETH will give around 300 USD profit if the attack is successful.

The protocol is designed in a manner where it is balanced most of the time (delta-neutral), using various incentives to bring the balance back. This means most of the time, the short (LPs) and long trader sides will be 100%-100%, respectively. The worst case it can go is 100%-120% as the system will prevent the skew to be more than 20%. Thus, there is a limit being imposed on the position size that a user can open. If the LP side is 100 ETH, and the current total long position size is 115 ETH. The maximum amount of position size one can open is left with 5 ETH. This is another constraint that the attacker faces.

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.

RealLTDingZhen commented 5 months ago

This issue should be Low/informational.

After the minimum execution time has elapsed, retrieve two prices from the Pyth oracle where the second price is higher than the first one.

Because of the minimum execution time protection, such arbitrage opportunity is only possible when arbitrageurs can steadily guess where the market is going. If the market falls during the minimum execution time, arbitrageurs suffer more losses.

shaka0x commented 5 months ago

This issue should be Low/informational.

After the minimum execution time has elapsed, retrieve two prices from the Pyth oracle where the second price is higher than the first one.

Because of the minimum execution time protection, such arbitrage opportunity is only possible when arbitrageurs can steadily guess where the market is going. If the market falls during the minimum execution time, arbitrageurs suffer more losses.

The attack can be profitable even with small price movements. Given that prices are reported every 400ms, the chances of obtaining an increase in price are very high.

nevillehuang commented 5 months ago

Agree with @xiaoming9090 given the high dependency of price fluctuations within small periods of time, I believe medium severity to be more appropriate

Czar102 commented 5 months ago

Fees are to make up for possible losses of this type, doing this attack atomically is practically the same as executing it within a few seconds.

Since this issue mentions a the fee bypass, and this is the only way it is of severity above Low, I think it should be duplicated with #212, since the impact of this issue can be High only because of the fee bypass.

Planning to accept the first escalation and consider this a duplicate of #212.

shaka0x commented 5 months ago

@Czar102 thank you for your feedback, but I don't understand in what sense this one could be considered as a duplicate of #212 What is explained in the issue is that in order to be profitable the gains due to the change in price have to be higher than the amount paid in fee. And I just point out that if we take into account that some fees can be avoided, as showed in #212, it is even easier to reach that profitability. But the issue is present independently of the fact that the fees can be avoided. The issue itself is not about avoiding fees, but about arbitraging the price.

Also, the performing the attack atomically is the only way of having control over the prices. To perform it in two blocks we have to rely on the second order not being executed by the keeper after we execute the first transaction in the previous block. By doing it atomically we ensure both orders are executed at the price we want, as long as we do it before the keeper (paying higher gas fees). If we execute the first order in block "n" and have to wait until block "n+1" to execute the second order, the keeper could just have executed it in block "n" after we executed ours.

Czar102 commented 5 months ago

I believe this issue is a low severity one without #212. Thinking alternatively, this issue is another severe impact of the core issue #212 – lack of fees results in both this attack and revenue losses for the LPs.

I believe counterarguments to all other points have been provided in https://github.com/sherlock-audit/2023-12-flatmoney-judging/issues/216#issuecomment-1959552564 and https://github.com/sherlock-audit/2023-12-flatmoney-judging/issues/216#issuecomment-1956126680.

shaka0x commented 5 months ago

I believe this issue is a low severity one without #212. Thinking alternatively, this issue is another severe impact of the core issue #212 – lack of fees results in both this attack and revenue losses for the LPs.

@Czar102 I politely ask you to read again the explanation of the issue. None of the calculations shown are counting on the effects of #212. There is no requirement of #212 to be present in order for the attack to be profitable. Even the escalator recognizes that in this message, only that considers the impact should not be high but medium, what I still disagree.

As I showed, the resultant profit of the attack is:

adjustmentSize * (secondPrice - firstPrice) - (adjustmentSize * tradeFees * 2)

That is without the outcome of the issue #212. If we take this outcome into account, the result would be:

adjustmentSize * (secondPrice - firstPrice) - (adjustmentSize * tradeFees)

But my assertion is based on the first case. I only pointed out, that the outcome of the attack could be even greater if we combine it with #212.

nevillehuang commented 5 months ago

I too fail to see how this issue is a duplicate of #212. They share completely separate root causes. With the impact described by LSW here, the issue is only worsened if price fluctuations is significant, so it should be downgraded to medium severity given dependency on external factors.

RealLTDingZhen commented 5 months ago

Sorry to disturb, but I still haven't figured out how this arbitrage works. After users announce leverage adjust, they have to wait 10s for their order to be executed. How could the arbitrageur know whether the value returned by oracle in the same block after ten seconds will be lower or higher? If the corresponding block does not fulfill the condition, then the transaction is likely to be executed by another keeper, making it unprofitable for the arbitrageurs.

If this path is not feasible, such logic flaw should not cause any financial loss, right?

shaka0x commented 5 months ago

The attacker does not know the future price, but can take advantage of price increases. The issue is that during the lifespan of the block many prices are valid (a new price is emitted every 400ms), and the flaw in the design is that multiple prices are allowed to be submitted in the same block. So the requirement is finding two prices during the lifespan of the block that make the arbitrage profitable.

In the worst case scenario for the attacker, they are not found or are found before keeper has executed the orders (here we are assuming that keepers will try to execute all orders ASAP and be faster, which is not necessarily the case), so the attacker will lose an amount equivalent to the fees paid. But specially in moments of high volatility the attacker is incentivized to perform the attack, as the potential profit compensates the possible losses in trade fees.

RealLTDingZhen commented 5 months ago

Ah I got it, when there are no fees, the arbitrageur's only risk is the market movement in 10s. In an balanced market, arbitrageurs can always make a profit through it.

Czar102 commented 5 months ago

@shaka0x @nevillehuang How I see it is that there are two elements to this issue:

  1. The ability to use the same price twice, which is the case even if it wouldn't be possible to do that in a single transaction. It's impossible for profits from this to exceed costs in fees, as shown by @xiaoming9090. This issue is informational.
  2. The ability to extract value if there are no fees. Then, this becomes a High severity issue, since the fees don't make up for possible losses, but this is really just another impact of lack of fees, hence I thought to duplicate it with #212.

I hope my approach makes sense now. In the end, whether this issue is invalidated or considered a duplicate of #212 won't impact the reward calculation at all.

@nevillehuang If you still think this issue should not be duplicated with #212, I'll consider it informational.

nevillehuang commented 5 months ago

@Czar102 Can you elaborate on point 1? Why would it be impossible for profits to exceed cost in fees given price fluctuations cannot be predicted? I believe this shouldn't be duplicated with #212.

shaka0x commented 5 months ago
  1. The ability to use the same price twice, which is the case even if it wouldn't be possible to do that in a single transaction. It's impossible for profits from this to exceed costs in fees, as shown by @xiaoming9090. This issue is informational.

@Czar102 The analysis of @xiaoming9090 shows that it is profitable as long as the price is increase is more than 0.2%. In fact can be very profitable, while the loss is capped to the trading fees. Can you explain why you think it says that it is impossible to be profitable?

Quoting his analysis:

My calculation shows that the price increase needs to be more than 0.2% to break even.

shaka0x commented 5 months ago

To add a bit of context, just looking at today's Pyth price feed for ETH/USD I have found some movements higher than 2% in a minute. That is, a movement 10 times bigger than the amount required to break even.

Czar102 commented 5 months ago

It seems I misunderstood the scope here. Is rETH/ETH or rETH/USD a tradeable pair here? I thought rETH/ETH is being traded, so there is no way there is a difference of 0.2% in price within 60 seconds.

shaka0x commented 5 months ago

Hey @Czar102 the intended pair used for the protocol is rETH/USD. However, as pointed in #90 and duplicates, there is no such pair in Chainlink, so the protocol will have to either use ETH/USD (original design intent) or adapt the code to use rETH/USD. In any case, the pair is against USD.

Czar102 commented 5 months ago

I see now. I believe this is a valid High severity issue. I think this attack persists even if executed non-atomically. @nevillehuang @shaka0x would you agree?

Planning to reject the escalation and leave the issue as is.

xiaoming9090 commented 5 months ago

@Czar102 Just wanted to add on. Other escalators (@0xLogos & @RealLTDingZhen) and I have raised points that the attackers have a high chance of losing their fees, potential risk faces, and external conditions required for executing this attack. Many attacks could be carried out when prices move up or down within a timeframe, but the potential risk involved might deter attackers from carrying out the attack. Thus, I believe these should be taken into consideration, and a Medium would be more appropriate.

shaka0x commented 5 months ago

I see now. I believe this is a valid High severity issue. I think this attack persists even if executed non-atomically. @nevillehuang @shaka0x would you agree?

Planning to reject the escalation and leave the issue as is.

The issue is that for performing it not atomically, you have to assume that keepers will not execute the orders ASAP. Executing it atomically, it is much easier to perform if keepers do not execute it ASAP, but still feasible if they do.

As for the risk of losses, in moments of high volatility it is easy to reach the required movement and the risk of losing the amount of the trade fees is bearable in contracts with the potential profit. Also, note that it is a necessary lag in the submission of the transaction (it is required to query the offchain price, build the request and submit the transaction), that for keepers is augmented, as they will have to process many orders in the same block. So the attacker can just cancel the second order if in the first seconds of the order being executable the requirements for profitability are not reached.

xiaoming9090 commented 5 months ago

I see now. I believe this is a valid High severity issue. I think this attack persists even if executed non-atomically. @nevillehuang @shaka0x would you agree?

Planning to reject the escalation and leave the issue as is.

@Czar102 The attack has to be carried out atomically. Shaka has highlighted https://github.com/sherlock-audit/2023-12-flatmoney-judging/issues/216#issuecomment-1957270402 and https://github.com/sherlock-audit/2023-12-flatmoney-judging/issues/216#issuecomment-1968837334 that the attack has to be executed atomically to be effective.

The attacker is effectively racing against time to find the right price deviation (two price data) within the 60-second limit to perform the attack within a single block. Also, if the keepers are robust, there is a high chance that the malicious orders would be executed early by other keepers, and the attacker would lose their fee before the attacker managed to find the right price deviation. In addition, it is not straightforward to cancel the order at the last minute if it is deemed unprofitable based on my explanation in this comment (https://github.com/sherlock-audit/2023-12-flatmoney-judging/issues/216#issuecomment-1959552564), Given these external conditions in place, I believe a Medium would be more appropriate.

Czar102 commented 5 months ago

I see. This seems to be borderline High/Med, I think considering it a valid Medium is justified. @shaka0x would you agree that there are some serious risks taken similar in size to the potential yield?

shaka0x commented 5 months ago

@Czar102 Yes, I agree that the attacker is assuming the risk of potential losses. My reasoning is that they are quite low in comparison with the potential profit, but I guess here we enter a subjective area.

Czar102 commented 5 months ago

Agree. Planning to consider this issue a valid unique Medium.

Czar102 commented 4 months ago

Result: Medium Unique

sherlock-admin2 commented 4 months ago

Escalations have been resolved successfully!

Escalation status: