DeFiFoundry
60,000 USDC
View results
Submission Details
Severity: medium
Valid

Risk-free Trades Through Withdraw Margin

Summary

By commitOrder then adjusting margin immediately after, a malicious trader gains control over whether his order is filled, allowing for risk-free trades and possible DOS of fillOffChainOrders.

Vulnerability Detail

During _fillOrder(), the transaction reverts if the account does not have enough margin:

function _fillOrder() {
...
// validates that the account has sufficient margin
tradingAccount.validateMarginRequirement(
ctx.requiredMarginUsdX18, tradingAccount.getMarginBalanceUsd(accountTotalUnrealizedPnlUsdX18),
ctx.orderFeeUsdX18.add(ctx.settlementFeeUsdX18)
);
...
}

A malicious trader can commit an order then immediately withdraw margin, putting his account below the margin requirement, if he does not want the order to be filled. When price or conditions moves in his favor, the trader can then depositMargin and allow the order to be filled.

Impact

This causes several issues:

  1. The malicious trader gains granular control over whether his trades are fulfilled or not, at the price he desires. Also, unlike the typical flow of commitOrder -> wait for order to fill, through this method the trader can achieve a filled order faster. These advantages may earn the malicious trader more profits at the expense of the protocol/LPs who are the counterparty providing the liquidity.

  2. Denial-of-Service(DOS) of fillOffChainOrders, which aims to fill a batch of orders. Other users' orders are not filled or delayed, resulting in loss of potential profits from trades. This can be performed repeatedly and at minimal cost to the attacker. Keepers also waste gas in the attempts to fill the orders.

Code Snippet

https://github.com/Cyfrin/2024-07-zaros/blob/main/src/perpetuals/branches/SettlementBranch.sol#L435
https://github.com/Cyfrin/2024-07-zaros/blob/main/src/perpetuals/branches/TradingAccountBranch.sol#L358

Tool used

Manual Review

Recommendation

During deposit/withdraw of margin cancel any pending orders by calling MarketOrder.load(ctx.tradingAccountId).clear(); similar to what is done during liquidations. This would prevent the trader from adjusting margin to prevent the order from filling.

Updates

Lead Judging Commences

inallhonesty Lead Judge
over 1 year ago
inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Appeal created

giraffe0x Submitter
over 1 year ago
inallhonesty Lead Judge
over 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

fillOffchainOrders reverts everything if a single order fails one of the multiple checks

If you send 1 cancel and 1 create it should still run the cancel, not revert everything.

The Keeper can be griefed by a user who withdraw's the collateral when having a pending position

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!