Bid Beasts

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

Auction time extension stacking bug

BidBeastsNFTMarketPlace::placeBid auction time extension stacking bug make sniping attack

Description

The auction logic should promote fairness by establishing a clear deadline (e.g., 3 days) and only extending the auction if a bid arrives close to the end. An ideal anti-sniping mechanism would reset the timer to “current block.timestamp + extension duration,” ensuring the end time remains consistently aligned with the intended gap from the latest bid.

That said, the current implementation accumulates extra time additively whenever the condition triggers (auctionEnd += 15 minutes). Consequently, the auction could overrun the 3-day threshold by a wide margin if multiple bids keep rolling in near the deadline. This creates an exploit opportunity for attackers to deploy bots and indefinitely postpone the auction's closure.

if (timeLeft < S_AUCTION_EXTENSION_DURATION) {
@> listing.auctionEnd = listing.auctionEnd + S_AUCTION_EXTENSION_DURATION;
emit AuctionExtended(tokenId, listing.auctionEnd);
}

Risk

Likelihood: High

  • Reason 1: This triggers every single time a bid arrives within less than 15 minutes of the deadline, since the extension logic consistently activates.

  • Reason 2: It's ripe for exploitation by trading bots that are scripted to fire off repeated bids right as the auction nears its close.

Impact: Medium

  • Impact 1: Auctions might stretch well beyond the intended 3-day cap, throwing off the predictable schedules that sellers and buyers rely on.

  • Impact 2: The platform could erode user confidence, as the auction mechanics fall short of the documented promise of an “exactly 3 days” timeframe.

Proof of Concept

This Foundry test demonstrates the auction could overrun the 3-day threshold

function test_placeBid_auctionMoreThan3Days() public {
_mintNFT();
_listNFT();
vm.prank(BIDDER_1);
market.placeBid{value: MIN_PRICE + 1}(TOKEN_ID);
BidBeastsNFTMarket.Listing memory listing = market.getListing(0);
console.log("Auction End:", listing.auctionEnd);
vm.warp(block.timestamp + 15 minutes - 1); // 15 min represent actually 30 days
vm.prank(BIDDER_2);
market.placeBid{value: MIN_PRICE * 2}(TOKEN_ID);
BidBeastsNFTMarket.Listing memory listing2 = market.getListing(0);
console.log("Auction End after second bid:", listing2.auctionEnd);
}
Logs:
Auction End: 901
Auction End after second bid: 1801

Recommended Mitigation

There's 2 option:

Keep anti-sniping extension

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);
}

Fixed hard deadline

- uint256 constant public S_AUCTION_EXTENSION_DURATION = 15 minutes;
function placeBid(uint256 tokenId) external payable isListed(tokenId) {
...
else {
requiredAmount = (previousBidAmount / 100) * (100 + S_MIN_BID_INCREMENT_PERCENTAGE);
require(msg.value >= requiredAmount, "Bid not high enough");
- 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;
- emit AuctionExtended(tokenId, listing.auctionEnd);
- }
+ emit AuctionExtended(tokenId, listing.auctionEnd);
}
}
Updates

Lead Judging Commences

cryptoghost Lead Judge 2 months 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.

Give us feedback!