BidBeastsNFTMarket::withdrawAllFailedCredits Leading to Theft of the Market's FundsThe withdrawAllFailedCredits function in the BidBeastsNFTMarket smart contract contains a critical authorization flaw. The function is designed to allow users to reclaim funds from bids that failed to be returned (e.g., when an outbid user is a contract that cannot receive Ether).
However, the function incorrectly uses the _receiver parameter to identify which credit balance to withdraw while unconditionally sending the funds to the function's caller (msg.sender). It never validates if msg.sender is the legitimate owner of the credits associated with the _receiver address. This creates a scenario where any malicious actor can drain the pending refunds of any other user by simply passing the victim's address as the _receiver argument.
Likelihood: High
The vulnerability is trivial to exploit. An attacker only needs to identify an address with a non-zero failedTransferCredits balance, which is public data on the blockchain. The attack requires no special privileges or complex conditions, only a single transaction call.
Impact: High
The impact is a direct and irreversible loss of user funds held within the contract. Since the function's purpose is to handle refunds, a significant amount of Ether could be vulnerable at any given time, leading to a complete drain of the contract's refund liquidity and severe reputational damage.
REJECTOR_1 (a contract that can't receive ETH) bids.
REJECTOR_2 outbids. The refund to REJECTOR_1 will fail, creating a credit.
BIDDER_1 buys the NFT. The refund to REJECTOR_2 will fail, creating another credit.
THE ATTACK: Attacker calls the vulnerable function with REJECTOR_1's address; the contract will be sending the REJECTOR_1's credits to the attacker up to when the market's balance is < REJECTOR_1'S credits.
The following Foundry test case demonstrates the vulnerability:
To resolve this vulnerability, the withdrawAllFailedCredits function must be modified to only operate on behalf of msg.sender. It should not accept an external address to determine which credit to withdraw. By tying the credit lookup and the payment directly to the caller, you ensure that users can only withdraw their own funds.
withdrawAllFailedCredits allows any user to withdraw another account’s failed transfer credits due to improper use of msg.sender instead of _receiver for balance reset and transfer.
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.