OrderBook

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

[M-02] Owner can mistakenly whitelist malicious token as sellable via setAllowedSellToken()

Author Revealed upon completion

Root + Impact

##Description
Normal Behavior:
The setAllowedSellToken() function is meant to let the owner allow or disallow ERC20 tokens that sellers can list in the order book. This ensures only well-known, safe tokens like wETH, wBTC, and wSOL are traded.

Specific Issue:
There is no validation to check whether the token being whitelisted is a valid ERC20 with standard behavior (e.g. decimals, transfer mechanics, no fee-on-transfer). A malicious or broken token can be added by mistake — especially in future governance upgrades — which may:

Behave unexpectedly during transfers.

Lock buyer funds.

Cause buy orders to fail or drain buyers.

function setAllowedSellToken(address _token, bool _isAllowed) external onlyOwner {
...
@> allowedSellToken[_token] = _isAllowed;
}

Risk

Likelihood:

Very likely during production operations or governance upgrades.

No interface checks mean any contract address can be whitelisted, even if it’s not an ERC20.

Impact:

Users may lose funds buying a malicious or broken token.

Buyers can be front-run or stuck in transactions that revert.

Sellers can list tokens that trap buyers' USDC, damaging platform trust.

Proof of Concept

A malicious token with a fake transfer() function is whitelisted using setAllowedSellToken().
Buyers lose USDC without receiving any tokens, as transfers silently fail or do nothing.

function transferFrom(address, address, uint256) public returns (bool) {
return true; // No actual transfer
}
function transfer(address, uint256) public returns (bool) {
return true;
}
}
// Owner mistakenly allows it
orderBook.setAllowedSellToken(address(fakeToken), true);
// Seller lists it
orderBook.createSellOrder(address(fakeToken), 1e18, 100e6, 3 days);
// Buyer "buys" but receives nothing. No revert either.
orderBook.buyOrder(orderId); // Buyer loses 100 USDC

Recommended Mitigation

function setAllowedSellToken(address _token, bool _isAllowed) external onlyOwner {
+ require(_token != address(0), "Invalid address");
+ require(_token != address(iUSDC), "USDC cannot be sellable");
+
+ // Optional safety check:
+ require(IERC20(_token).totalSupply() > 0, "Token does not behave as ERC20");
allowedSellToken[_token] = _isAllowed;
emit TokenAllowed(_token, _isAllowed);
}

Maintain a fixed allowlist in the constructor or restrict updates via multisig/governance only.

Updates

Lead Judging Commences

yeahchibyke Lead Judge about 9 hours ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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