# Attacker can drain all ETH from AuctionDemo when block.timestamp == auctionEndTime

Inclusive >= timestamp checks let an attacker bid, claim, and cancel bids in the same block, double-refunding bids and draining AuctionDemo ETH.

- Payout: Contest reward
- Severity: high
- Program: NextGen
- Credited: smiling\_heretic
- Disclosed: 2024-01-08
- Write-up quality: 8/10
- Original: https://github.com/code-423n4/2023-10-nextgen-findings/issues/1323
- Library page: https://bugbountylibrary.com/r/c4%3A2023-10-nextgen%3AH-02
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:chained technique:source-review vuln:business-logic vuln:race-condition

**Target:** AuctionDemo.sol auction bidding/claim contract
**Root cause:** claimAuction uses >= auctionEndTime so it overlaps with the bidding phase at exactly auctionEndTime, and claimAuction refunds non-winning bids without setting status=false, unlike cancelBid.
**Steps:**
1. Wait until block.timestamp == minter.getAuctionEndTime(tokenId).
2. Call `participateToAuction{value: 1.01 ether}(tokenId)` (and more bids) to become winner.
3. Call `claimAuction(tokenId)` — receives NFT plus refunds on non-winning bids without marking status false.
4. Call `cancelAllBids(tokenId)` — gets refunded again on all bids including the winning one.
5. Net: NFT for free and contract ETH drained (attacker 5->7.03 ETH, auction balance 0).
**How found:** Code-reading of the auction phase checks noticed `>=`/`<=` inclusive inequalities create a one-block overlap where both phases are active; then noticed claimAuction refunds lack the status=false guard present in cancelBid, enabling double refund.
**Exploitation:** Attacker times a transaction to the exact auctionEndTime block, outbids to win, claims the NFT (getting refunds on losing bids), then cancels all bids to be refunded a second time on the same bids, extracting ETH deposited for other auctions.
**Escalation:** Drains ETH belonging to all other concurrently running auctions, not just the targeted one.
**Insight:** When a contract has distinct time phases, check whether boundary comparisons (>= vs >) let both phases be active in the same block; then diff refund/withdrawal paths for missing 'already-paid' status flags that one path sets and another omits.
