Bid Beasts

First Flight #49
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: low
Valid

Bid equal to minimum price reverts and permanently locks sent ETH.

Root + Impact

Description

  • Normal Behavior: A bid equal to the minimum price should be accepted as the starting bid, as it meets the price requirement.

  • Specific Issue: The validation for the first bid uses a strictly greater than comparison (> minPrice). If a bidder sends an amount exactly equal to listing.minPrice, the transaction reverts. Crucially, the sent ETH is locked permanently in the contract because the refund logic is only executed for a previous bidder, which does not exist for the first bid.

// Root cause in the codebase with @> marks to highlight the relevant section
// ... inside placeBid ...
if (previousBidAmount == 0) {
requiredAmount = listing.minPrice;
require(msg.value @> > <@ requiredAmount, "First bid must be > min price"); // Reverts if msg.value == minPrice
// ...
}
// ... if the require fails, the function reverts before any refund/payout.

Risk

Likelihood:

  • The bug is easy to trigger; any user attempting to bid exactly the minimum price will cause it.

  • The design of the function ensures the funds remain locked upon this specific reversion.

Impact:

  • Permanent loss of funds equal to the minimum price.

  • Allows a griefing attack to continuously lock small amounts of ETH in the contract.

Proof of Concept

This PoC demonstrates a user sending a value (1 ether) that is exactly equal to MIN_PRICE, causing the transaction to revert while the 1 ether remains locked in the contract's balance.

function test_fail_placeFirstBid_exactMinPrice_locksFunds() public {
// Setup: Mint and List NFT (MIN_PRICE is 1 ether)
_mintNFT();
_listNFT();
uint256 minPrice = market.S_MIN_NFT_PRICE();
uint256 contractBalanceBefore = address(market).balance;
// BIDDER_1 attempts to bid exactly MIN_PRICE (1 ether)
vm.prank(BIDDER_1);
vm.expectRevert("First bid must be > min price");
market.placeBid{value: minPrice}(TOKEN_ID);
// Assert: The 1 ether is now locked in the contract
assertEq(address(market).balance, contractBalanceBefore + minPrice, "Funds were locked in contract");
}

Recommended Mitigation

The comparison for the first bid check must be changed from strictly greater than (>) to greater than or equal to (>=). This simple change allows a bid equal to the minimum price to be valid, thus preventing the reversion that locks the funds.

- require(msg.value > requiredAmount, "First bid must be > min price");
+ require(msg.value >= requiredAmount, "First bid must be >= min price"); // FIX: Allows bids equal to minPrice
Updates

Lead Judging Commences

cryptoghost Lead Judge 29 days ago
Submission Judgement Published
Validated
Assigned finding tags:

BidBeasts Marketplace: First Bid > Instead of >=

First bid validation uses > instead of >=, preventing valid starting bids.

Support

FAQs

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