# Virtual impacts can be trivially bypassed via structuring

GMX Synthetics virtual price impact threshold can be bypassed by splitting a large order into smaller sub-threshold orders in the same block, defeating oracle-manipulation protection.

- Payout: Contest reward
- Severity: medium
- Program: Gmx
- Credited: IllIllI
- Disclosed: 2022-09-22
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-02-gmx-judging/issues/145
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-02-gmx%3AM-27
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic vuln:oracle-manipulation

**Target:** GMX Synthetics PositionPricingUtils.getPriceImpactUsd virtual inventory pricing
**Root cause:** The virtual price impact is only applied when it exceeds a threshold proportional to the current order's usdDelta; smaller orders fall below the threshold and skip the global virtual impact entirely.
**Steps:**
1. Observe getPriceImpactUsd returns priceImpactUsdForVirtualInventory only if it exceeds thresholdPriceImpactUsd = usdDelta * thresholdImpactFactorForVirtualInventory.
2. Split a large order into multiple smaller orders each with usdDelta small enough that the virtual price impact stays under its per-order threshold.
3. Submit all small orders in the same block to manipulate the oracle price while each order avoids the global virtual impact.
**How found:** Code reading of PositionPricingUtils.getPriceImpactUsd: noticed the threshold is computed from the current order's usdDelta rather than total position size, so per-order splitting evades the check.
**Exploitation:** Attacker fragments a large position into sub-threshold orders executed in one block, so no single order triggers the virtual price impact, allowing oracle price manipulation that the mechanism was meant to deter.
**Insight:** When a manipulation deterrent is gated by a per-transaction threshold, check whether the same actor can fragment into multiple sub-threshold calls within one block; thresholds should key off aggregate position/account state, not the single order delta.
