# Highest bidder can withdraw his collateral due to a missing check in _cancelAllBids

Missing highest-bidder check in _cancelAllBids lets the leading bidder withdraw collateral, still win the auction, and drain locked funds.

- Payout: Contest reward
- Severity: high
- Program: Radicalxchange
- Credited: 0rpse
- Disclosed: 2024-02-09
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2024-02-radicalxchange-judging/issues/14
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-02-radicalxchange%3AH-1
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:incomplete-fix technique:source-review vuln:access-control vuln:business-logic

**Target:** EnglishPeriodicAuctionInternal.sol auction contract
**Root cause:** _cancelAllBids loops all rounds crediting collateral to availableCollateral without the require that blocks the current highest bidder, and does not reset l.highestBids[tokenId][round].bidder.
**Steps:**
1. Bob bids 10 ETH, becoming highestBids[tokenId][round].bidder.
2. Bob calls `cancelAllBidsAndWithdrawCollateral()`, invoking `_cancelAllBids` which credits his 10 ETH to availableCollateral without the highest-bidder require.
3. `_withdrawCollateral` pays Bob back 10 ETH while highestBids still records Bob as leader.
4. Auction ends; Bob wins and his 10 ETH bidAmount is credited to the previous oldBidder's availableCollateral.
5. oldBidder withdraws 10 ETH from other users' locked collateral, leaving a shortfall that later withdrawals cannot cover.
**How found:** Compared _cancelBid, which has a require blocking the highest bidder from cancelling, against _cancelAllBids, which lacks that check and also fails to reset highestBids.
**Exploitation:** Attacker bids to become highest bidder, calls cancelAllBidsAndWithdrawCollateral to reclaim collateral, still wins the auction for free; the winning bid is paid out of other bidders' locked collateral, draining the contract if repeated.
**Escalation:** Repeating across auctions drains contract balance so all users lose locked collateral.
**Insight:** When a guard exists in one cancel/withdraw path, audit every sibling path (batch/all variants) for the same guard and for state (highestBids) that must be reset alongside collateral.
