OrderBook

First Flight #43
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Valid

Front-running Attack in buyOrder

Front-running Attack in buyOrder

Description

The buyOrder() function is vulnerable to front-running attacks where malicious sellers can monitor the mempool for incoming buy transactions and modify their order prices at the last moment, potentially extracting additional value from buyers.

The buyOrder(uint256 _orderId) function only requires an orderId parameter and executes the trade at whatever price is currently set in the order. This design allows sellers to modify their order prices via the amendSellOrder() function right before a buyer's transaction is mined.

// @audit-issue - Front-running attack in buyOrder, it only accepts an orderId, and not guarantee of the accepted price/amount.
@> function buyOrder(uint256 _orderId) public {
// ...
}

Risk

Likelihood: High

  • This can happen on any buyOrder() call. As the mempool is publicly visible, and the orderbook is a public contract, anyone can see the orderbook and the orders.

Impact: High

  • Buyers may pay significantly more than the originally advertised price

  • Attackers can extract additional value through price and amout manipulation

  • Market participants lose trust in the order book's price discovery mechanism

  • Users cannot rely on displayed prices and values when placing orders

  • Potential for MEV extraction by sophisticated attackers

Proof of Concept

  1. Attacker creates an attractive order

  2. Attacker scans the mempool

  3. User accepts the order and calls buyOrder()

  4. Attacker adjusts the order with more gas(), frontrunning the user

  5. User pays the new amount+price that the attacker decided

// Attacker's order creation
uint256 orderId = orderBook.createSellOrder(
address(wETH),
1 ether,
2000 * 1e6, // 2000 USDC for 1 ETH (attractive price)
1 hours
);
// Buyer submits transaction to buy the order
orderBook.buyOrder(orderId); // Pending in mempool
// Attacker detects the pending transaction and front-runs with price increase
// and making sure to spend more gas to front-run
orderBook.amendSellOrder(
orderId,
1 wei, // Only give 1 wei to the buyer
10000 * 1e6, // Increased to 10_000 USDC
1 hours
);
// Buyer's transaction executes at the higher price for only 1 wei

Recommended Mitigation

1. Price Commitment Mechanism

Implement a commitment-based system where buyers specify a maximum price and minimum amount they're willing to pay:

function buyOrder(uint256 _orderId, uint256 _maxPrice, uint256 _minAmount) public {
Order storage order = orders[_orderId];
// Validate price commitment
if (order.priceInUSDC > _maxPrice) revert PriceExceedsMaximum();
if (order.amountToSell < _minAmount) revert AmountBelowMinimum();
// ... rest of the function
}

(optionally consider to ONLY allow to change the price and not amount, to make verification and buying easier)

2. Order Hash Verification

Use cryptographic commitments to prevent price modifications:

function createSellOrder(
address _tokenToSell,
uint256 _amountToSell,
uint256 _priceInUSDC,
uint256 _deadlineDuration,
bytes32 _orderHash // Hash of order parameters
) public returns (uint256) {
// Store the hash and verify it matches on buyOrder
}
function buyOrder(uint256 _orderId, bytes32 _expectedOrderHash) public {
// Verify the order hash hasn't changed
if (keccak256(abi.encodePacked(order.parameters)) != _expectedOrderHash) {
revert OrderModified();
}
}

3. Remove the amendSellOrder function

If a user wants to modify the order, they can cancel and create a new order.

Updates

Lead Judging Commences

yeahchibyke Lead Judge
4 months ago
yeahchibyke Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Appeal created

neomartis Submitter
4 months ago
yeahchibyke Lead Judge
4 months ago
yeahchibyke Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Buy orders can be front-run and amended maliciously

A malicious seller can front-run a buy order for their order, and decrease the amount of assets to be sold. If the price is unchanged, the buy transaction fulfills, but the buyer gets lesser amount than expected.

Support

FAQs

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