Normally, placeBid() should safely handle bid updates and ETH transfers:
Refund the previous highest bidder.
Transfer the NFT and funds to the seller when a “buy-now” is triggered.
Update internal bid/listing state.
However, the function performs multiple external calls sending ETH** **(_payout() and _executeSale()) before all state updates are finalized.
These calls use low-level .call{value: amount}(""), which allows the recipient’s fallback to execute arbitrary code.
Because some state variables (bids[tokenId], listings[tokenId], failedTransferCredits) are modified after these calls, a malicious bidder can re-enter and call other public functions in the contract during the same transaction.
Likelihood:
Any previous bidder or seller with a contract wallet can supply a malicious fallback.
During these external calls they can re-enter other functions (e.g. unlistNFT, takeHighestBid, settleAuction) while bids/listings are in an inconsistent state.
Impact:
Manipulate auction results (e.g., cancel or replace bids mid-execution).
Withdraw funds multiple times or bypass minimum bid logic.
Potential theft of ETH or NFTs if reentrancy is exploited to re-trigger payout logic.
Deploy MaliciousBidder, call initialBid(), then have another user outbid it.
When placeBid() tries to refund the malicious bidder, the fallback fires and unlistNFT executes before placeBid finishes updating state.
Alternatively, use ReentrancyGuard (nonReentrant) modifier from OpenZeppelin to block re-entrancy entirely.
Consider using the pull patern for all ETH transfers (users call a separate withdraw function).
BidBeast Marketplace has a Medium-severity reentrancy vulnerability in its "buy-now" feature that allows an attacker to disrupt the platform by blocking sales or inflating gas fees for legitimate users.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.