OrderBook

First Flight #43
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Impact: medium
Likelihood: medium
Invalid

`OrderBook::amendSellOrder` doesn't follow the CEI, so the attackers reentrance attack is possible.

OrderBook::amendSellOrder doesn't follow the CEI, so the attackers' reentrance attack is possible.

Description

  • The amendSellOrder function allows users to modify their existing sell orders by changing the amount to sell, price, or deadline.

  • The function violates the CEI (Checks-Effects-Interactions) pattern by making external token transfers before updating the order state, allowing malicious tokens to re-enter the function and drain additional tokens.

function amendSellOrder(...) public {
Order storage order = orders[_orderId];
// ... validation checks ...
if (_newAmountToSell < order.amountToSell) {
uint256 diff = order.amountToSell - _newAmountToSell;
@> token.safeTransfer(order.seller, diff); // INTERACTION first
}
@> order.amountToSell = _newAmountToSell; // EFFECT after
@> order.priceInUSDC = _newPriceInUSDC;
@> order.deadlineTimestamp = newDeadlineTimestamp;
}

Risk

Likelihood:

  • An attacker deploys a malicious ERC20 token with callback functionality and creates sell orders with it

  • The attacker calls amendSellOrder to reduce the order amount, triggering the safeTransfer back to the attacker which executes the malicious callback

Impact:

  • The attacker can drain the contract's balance of their malicious token by executing multiple transfers in a single transaction through reentrancy

  • The attack scope is limited to malicious tokens controlled by the attacker and does not affect legitimate tokens like wETH, wBTC, or wSOL

Proof of Concept

contract MaliciousToken {
OrderBook public orderBook;
uint256 public attackCount;
function transfer(address to, uint256 amount) external returns (bool) {
// Reentrancy attack during transfer
if (msg.sender == address(orderBook) && attackCount < 3) {
attackCount++;
orderBook.amendSellOrder(1, 100 ether, 1000, 1 days);
}
return true;
}
}

Attack Flow:

  1. Attacker deploys malicious token and creates sell order with 1000 tokens

  2. Calls amendSellOrder to reduce amount to 100 tokens

  3. Contract transfers 900 tokens back, triggering malicious callback

  4. Callback re-enters amendSellOrder before state update

  5. Process repeats, draining more tokens than entitled

Recommended Mitigation

Follow the CEI pattern by updating state before external calls:

function amendSellOrder(...) public {
Order storage order = orders[_orderId];
// ... validation checks ...
+ uint256 oldAmountToSell = order.amountToSell;
+
+ // Update order details FIRST (EFFECTS)
+ order.amountToSell = _newAmountToSell;
+ order.priceInUSDC = _newPriceInUSDC;
+ order.deadlineTimestamp = newDeadlineTimestamp;
- if (_newAmountToSell < order.amountToSell) {
- uint256 diff = order.amountToSell - _newAmountToSell;
+ if (_newAmountToSell < oldAmountToSell) {
+ uint256 diff = oldAmountToSell - _newAmountToSell;
token.safeTransfer(order.seller, diff);
}
- // Update order details
- order.amountToSell = _newAmountToSell;
- order.priceInUSDC = _newPriceInUSDC;
- order.deadlineTimestamp = newDeadlineTimestamp;
}

This prevents reentrancy by updating the order state immediately after validation and before any external calls. If a malicious token attempts to re-enter, the order will already reflect the new values, preventing additional unauthorized transfers.

Updates

Lead Judging Commences

yeahchibyke Lead Judge
about 1 month ago
yeahchibyke Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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