Bid Beasts

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

Auction Extension adds to Past Time Instead of Current Time may lock NFTs in auction longer than sellers expect

Medium: Auction Extension Adds to Past Time Instead of Current Time

Description

  • The auction extension mechanism extends the auction deadline by 15 minutes when a bid is placed near the end to prevent last-second sniping.

  • The extension incorrectly adds time to the existing deadline rather than setting a new deadline from the current timestamp, potentially creating unexpectedly long auctions.

if (timeLeft < S_AUCTION_EXTENSION_DURATION) {
listing.auctionEnd = listing.auctionEnd + S_AUCTION_EXTENSION_DURATION; // @> Adds to old deadline, not current time
emit AuctionExtended(tokenId, listing.auctionEnd);
}

Risk

Likelihood:

  • Occurs when bids are placed with less than 15 minutes remaining

  • Happens in competitive auctions with multiple last-minute bidders

Impact:

  • Auctions can be extended beyond the intended 15-minute extension

  • Creates inconsistent extension behavior based on exact timing

  • May lock NFTs in auction longer than sellers expect

Proof of Concept

This test demonstrates how the auction extension logic adds time to the old deadline instead of setting a new deadline from the current time, causing extensions to be longer than intended.

function test_AuctionExtensionTimingBug() public {
_mintNFT();
_listNFT();
// Place first bid to start auction
vm.prank(BIDDER_1);
market.placeBid{value: 1.1 ether}(TOKEN_ID);
// Auction ends at block.timestamp + 15 minutes (900 seconds)
uint256 originalEnd = market.getListing(TOKEN_ID).auctionEnd;
// Fast forward to 10 minutes before end (5 minutes left)
vm.warp(originalEnd - 300); // 300 seconds before end
// Place another bid when 5 minutes remaining
vm.prank(BIDDER_2);
market.placeBid{value: 1.2 ether}(TOKEN_ID);
uint256 newEnd = market.getListing(TOKEN_ID).auctionEnd;
// Expected: newEnd = block.timestamp + 900 = (originalEnd - 300) + 900 = originalEnd + 600
// Actual: newEnd = originalEnd + 900
assertEq(newEnd, originalEnd + 900); // Bug: adds full extension to old time
// The auction was extended by 900 seconds from the OLD deadline
// Instead of 900 seconds from CURRENT time
// Result: 20 minute extension instead of 15 minutes from current time
uint256 actualExtension = newEnd - block.timestamp;
assertEq(actualExtension, 1200); // 20 minutes, not 15!
}

Recommended Mitigation

Set the auction end time relative to the current timestamp rather than adding to the existing deadline. This ensures consistent 15-minute extensions regardless of when the bid is placed.

uint256 timeLeft = 0;
if (listing.auctionEnd > block.timestamp) {
timeLeft = listing.auctionEnd - block.timestamp;
}
if (timeLeft < S_AUCTION_EXTENSION_DURATION) {
- listing.auctionEnd = listing.auctionEnd + S_AUCTION_EXTENSION_DURATION;
+ listing.auctionEnd = block.timestamp + S_AUCTION_EXTENSION_DURATION;
emit AuctionExtended(tokenId, listing.auctionEnd);
}

This change ensures that:

  • Every extension gives bidders exactly 15 minutes from the current time

  • The auction cannot be extended indefinitely through timing manipulation

  • Behavior is predictable and consistent for all participants

Updates

Lead Judging Commences

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

BidBeast Marketplace: Auction Duration Miscalculation

BidBeast marketplace contains a flaw in its auction timing mechanism. This causes the contract to miscalculate the actual end time of an auction, resulting in auctions that either conclude prematurely or run longer than specified.

Support

FAQs

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