OrderBook

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

Arbitrary Price Inflation

Arbitrary Price Inflation Risk via Order.priceInUSDC in OrderBook.sol

Description

  • Normal Behavior: Sellers create sell orders by specifying the token they’re offering, the amount, and the priceInUSDC they want to receive. Buyers then purchase the token by paying the specified USDC amount.

  • Issue: The contract allows sellers to specify any arbitrary priceInUSDC, regardless of the real market value of the token being sold. Even with whitelisted, a malicious seller can list a grossly inflated price (e.g., 1 wETH for 4,000 USDC) and scam unsuspecting buyers. The contract does not validate prices against any on-chain oracle or external reference and blindly accepts any price input.

function createSellOrder(
address _tokenToSell,
uint256 _amountToSell,
// Arbitrary price input
@> uint256 _priceInUSDC,
uint256 _deadlineDuration
) public returns (uint256) {
if (!allowedSellToken[_tokenToSell]) revert InvalidToken();
if (_amountToSell == 0) revert InvalidAmount();
if (_priceInUSDC == 0) revert InvalidPrice();
if (_deadlineDuration == 0 || _deadlineDuration > MAX_DEADLINE_DURATION) revert InvalidDeadline();
uint256 deadlineTimestamp = block.timestamp + _deadlineDuration;
uint256 orderId = _nextOrderId++;
IERC20(_tokenToSell).safeTransferFrom(msg.sender, address(this), _amountToSell);
// Store the order
orders[orderId] = Order({
id: orderId,
seller: msg.sender,
tokenToSell: _tokenToSell,
amountToSell: _amountToSell,
// Arbitrary price input
@> priceInUSDC: _priceInUSDC,
deadlineTimestamp: deadlineTimestamp,
isActive: true
});
emit OrderCreated(orderId, msg.sender, _tokenToSell, _amountToSell, _priceInUSDC, deadlineTimestamp);
return orderId;
}

Risk

Likelihood:

  • Occurs whenever a buyer relies on the frontend UI or static off-chain listings without manually verifying token value

  • Common when buyers are rushed, unfamiliar with token values, or assume the platform enforces fair pricing

Impact:

  • Leads to economic scams and loss of funds

  • Buyer pays significantly more than market value for a legitimate token

  • Reduces user trust in the platform and may lead to regulatory risk

Proof of Concept

  1. Seller lists 1 wSol for 300 USDC (assuming real market price: ~100 USDC).

  2. Buyer sees “1 wSol” and assumes the price is fair.

  3. Buyer calls buyOrder() and transfers 300 USDC for something worth only ~100 USDC.

Trade executes as expected — no bugs — but buyer is effectively scammed.

Paste the function below in your test file and update the setUp function

address attacker = makeAddr("attacker");
// update the setup function
function setUp() public {
// ...
wsol.mint(attacker, 5);
// ...
}
function test_arbitraryPriceInflation() public {
vm.startPrank(attacker);
// assume real price of sol => 100 usdc (1e18 wSol = 100e6 USDC)
wsol.approve(address(book), 1e18);
uint256 attackerId = book.createSellOrder(address(wsol), 1e18, 300e6, 2 days);
vm.stopPrank();
vm.startPrank(dan);
usdc.approve(address(book), type(uint256).max);
book.buyOrder(attackerId);
vm.stopPrank();
// Using magic number isn't a good practice but, I'm just playing around 😊
uint256 balanceAfter = 300e6 - (300e6 * (3 / 100));
assertEq(usdc.balanceOf(attacker), balanceAfter);
}

Recommended Mitigation

Integrate a Price Oracle (e.g., Chainlink)
Use a trusted on-chain price feed (like Chainlink) to get the real-time market value of the token being sold. This prevents sellers from setting outrageously inflated prices

Updates

Lead Judging Commences

yeahchibyke Lead Judge
14 days ago
yeahchibyke Lead Judge 11 days ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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