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
4 months ago
yeahchibyke Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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