# placeBid() Possible participation in auctions that have been modified

placeBid() identifies auctions only by comptroller, so a bidder can unknowingly join a restarted auction with different debt/seized terms and lose funds.

- Payout: Contest reward
- Severity: medium
- Program: Venus Protocol
- Credited: bin2chen
- Disclosed: 2023-08-09
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-05-venus-findings/issues/62
- Library page: https://bugbountylibrary.com/r/c4%3A2023-05-venus%3AM-14
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:business-logic vuln:race-condition

**Target:** placeBid() auction bidding function in Venus Comptroller/auction contract
**Root cause:** placeBid() keys the auction solely on comptroller and does not verify the auction's startBlock, so a stale/ended auction that gets restarted (with different type, debt, and seizedRiskFund) is silently joined by a pending bid transaction.
**Steps:**
1. Alice sees auction {type=LARGE_RISK_FUND, debt=100, seizedRiskFund=100} in UI and submits `placeBid(comptroller, bidBps)`.
2. Before her tx executes, auction becomes stale (>waitForFirstBidder) or ends (>nextBidderBlockLimit) and Bob restarts it, e.g. {type=LARGE_POOL_DEBT, debt=100000, seizedRiskFund=100} or {debt=100, seizedRiskFund=0}.
3. Alice's tx executes against the new auction since only `comptroller` is checked; she pays high debt for little seizedRiskFund.
4. Fix: add `auctionStartBlock` param and `require(auction.startBlock == auctionStartBlock)`.
**How found:** Code reading of placeBid(): noticed the auction is looked up only by comptroller and that _isStale/restart logic can replace the auction, so a pending bid has no binding to the auction version the user intended.
**Exploitation:** A bidder's transaction sits in the mempool while the auction is restarted by another party; the bid then executes against the new auction terms, causing the bidder to overpay debt for minimal seizedRiskFund. No attacker profit is required—loss arises from the race between restart and bid execution.
**Insight:** When a function references a mutable, restartable state object by a stable key (e.g. comptroller), check whether the object can be replaced between tx submission and execution; require a version/startBlock commitment to bind the user's intent.
