Bid Beasts

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

Auction time manipulation via cumulative extension on new bids (last-minute bid exploit)

The placeBid function extends listing.auctionEnd by S_AUCTION_EXTENSION_DURATION relative to the previous auctionEnd rather than block.timestamp. This allows malicious bidders to repeatedly place last-minute bids, cumulatively extending the auction indefinitely. This is a lofic flow in auction timer handling that can be exploited for bid sniping or denial-of-auction.

Description

  • When a new bid is placed the extension should be relative to the current time, ensuring that the auction eventually ends.

  • In this contract, the auction is extended as listing.auctionEnd = listing.auctionEnd + S_AUCTION_EXTENSION_DURATION . Since this uses the previous auctionEnd rather than block.timestamp, a malicious bidder can place successive last-minute bids to continuously extend the auction.

// Root cause in the codebase with @> marks to highlight the relevant section
function placeBid(uint256 tokenId) external payable isListed(tokenId) {
// Rest Of the function
if (timeLeft < S_AUCTION_EXTENSION_DURATION) {
@> listing.auctionEnd = listing.auctionEnd + S_AUCTION_EXTENSION_DURATION;
emit AuctionExtended(tokenId, listing.auctionEnd);
}
}

Risk

Likelihood:

  • Denial-of-auction: Legitimate bidders may be unable to settle the auction, disrupting marketplace operations.

  • Economic manipulation: Attackers can repeatedly extend the auction to force other bidders to spend more gas or manipulate bid timing.

  • People can get fed up of the system and inturn reputational loss

Impact:

  • Any bidder placing a last-minute bid can trigger the cumulative extension, making exploitation trivial.

Proof of Concept

  • As the test output we can see that the correct time should be incremented in the current block.timestamp

  • Rather it is updating the 15 minutes in context of the previous listing.auctionEnd which is the issue here


function test_AuctionIncreaseTime() public {
_mintNFT();
_listNFT();
//// 1st bid
vm.prank(BIDDER_1);
market.placeBid{value: 2 ether}(TOKEN_ID);
(,,,uint auctionendafterfirst,) = market.listings(TOKEN_ID);
console.log("auction end after first bid", auctionendafterfirst);
vm.warp(block.timestamp + 10 minutes);
/// 2nd bid
vm.prank(BIDDER_2);
market.placeBid{value: 3 ether}(TOKEN_ID);
(,,,uint auctionendaftersecond,) = market.listings(TOKEN_ID);
uint256 bidtime = block.timestamp;
console.log("auction end after second bid", auctionendaftersecond);
console.log("The correction auction extended time should be : ",bidtime + 15 minutes);
console.log("second bid time :", bidtime);
assertEq(auctionendaftersecond,bidtime + 15 minutes , "The times are not matching ");
}
/*Output
Logs:
auction end after first bid 901
auction end after second bid 1801
The correction auction extended time should be : 1501
second bid time : 601
Suite result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 1.36ms (483.40µs CPU time)
Ran 1 test suite in 10.86ms (1.36ms CPU time): 0 tests passed, 1 failed, 0 skipped (1 total tests)
Failing tests:
Encountered 1 failing test in test/anyoncecanwithdraw.t.sol:BidBeastsNFTMarketTest
[FAIL: The times are not matching : 1801 != 1501] test_AuctionIncreaseTime() (gas: 365812)
*/

Recommended Mitigation

  • This clearly solves the issue by apping the 15 minutes to the current time not listing.auctionEnd

- listing.auctionEnd = listing.auctionEnd + S_AUCTION_EXTENSION_DURATION;
+ listing.auctionEnd = block.timestamp + S_AUCTION_EXTENSION_DURATION;
Updates

Lead Judging Commences

cryptoghost Lead Judge about 1 month 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.