Root + Impact
Description
## Summary
The OrderBook contract allows sellers to buy their own orders, enabling market manipulation
and pump & dump attacks. Attackers can create artificial trading volume and price movements
to trick other users into buying at inflated prices, leading to significant financial losses.
## Vulnerability Details
The `buyOrder()` function lacks a check to prevent sellers from purchasing their own orders:
function buyOrder(uint256 _orderId) public {
Order storage order = orders[_orderId];
if (order.seller == address(0)) revert OrderNotFound();
if (!order.isActive) revert OrderNotActive();
if (block.timestamp >= order.deadlineTimestamp) revert OrderExpired();
}
--Critical Issues:
- Sellers can buy their own orders to create fake volume
- Enables artificial price manipulation and pump & dump schemes
- Other users are tricked by fake buying pressure
- Classic market manipulation attack vector
## Impact
- Market manipulation: Artificial volume and price movements
- Pump & dump attacks: Attackers profit from inflated prices
- User deception: Other traders follow fake momentum
- Financial losses: Users buy at artificially inflated prices
- Protocol integrity: Compromises fair market operation
- Regulatory risk: Market manipulation is illegal in many jurisdictions
## Affected Functions
- `buyOrder()` - Lines 193-210 (missing self-buy prevention)
Risk
Likelihood:
Impact:
Proof of Concept
# Proof of Concept
1. Attacker creates multiple sell orders at different price points
2. Attacker buys their own orders to create fake buying pressure
3. Other users see "volume" and "price movement"**
4. Users are tricked into buying at inflated prices
5. Attacker profits from the artificial price pump
## The Problem
No check prevents sellers from buying their own orders to manipulate the market:
function buyOrder(uint256 _orderId) public {
Order storage order = orders[_orderId];
if (order.seller == address(0)) revert OrderNotFound();
if (!order.isActive) revert OrderNotActive();
if (block.timestamp >= order.deadlineTimestamp) revert OrderExpired();
order.isActive = false;
uint256 protocolFee = (order.priceInUSDC * FEE) / PRECISION;
}
## Attack Scenario
- Attacker spends 1000 USDC on 33 fake trades (3% fees = 30 USDC)
- Creates artificial volume that tricks other users
- Price pumps 15%*due to perceived demand
- Attacker sells at inflated price for 1150 USDC
- Net profit: 150 USDC - 30 USDC = 120 USDC profit
Recommended Mitigation
# Mitigation
The `buyOrder()` function allows sellers to buy their own orders, enabling market manipulation
and pump & dump attacks that can trick other users into buying at inflated prices.
**Vulnerable Code:**
// Lines 193-210: buyOrder()
function buyOrder(uint256 _orderId) public {
Order storage order = orders[_orderId];
// Validation checks
if (order.seller == address(0)) revert OrderNotFound();
if (!order.isActive) revert OrderNotActive();
if (block.timestamp >= order.deadlineTimestamp) revert OrderExpired();
// Missing check to prevent self-buy
}
--The Problem:
Attackers can buy their own orders to create fake volume and manipulate prices,
leading to pump & dump schemes that harm other users.
## How to Fix
Add a critical check to prevent sellers from buying their own orders:
function buyOrder(uint256 _orderId) public {
Order storage order = orders[_orderId];
// Validation checks
if (order.seller == address(0)) revert OrderNotFound();
if (!order.isActive) revert OrderNotActive();
if (block.timestamp >= order.deadlineTimestamp) revert OrderExpired();
if (order.seller == msg.sender) revert("Cannot buy own order"); // CRITICAL: Prevent market manipulation
}
--The Fix:
Now sellers cannot buy their own orders, preventing market manipulation and protecting
users from pump & dump attacks.
## Alternative: Add Custom Error
error CannotBuyOwnOrder();
// In function:
if (order.seller == msg.sender) revert CannotBuyOwnOrder();
--Recommendation:
This fix is CRITICAL to prevent market manipulation and protect users from financial losses.