Bid Beasts

First Flight #49
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: high
Valid

Insecure Withdraw Logic in `bidBeastMarketPlace:: withdrawAllFailedCredits` Function , any user can pass another user’s address (with failed credits) as \_receiver and drain their funds **Description:** The `bidBeastMarketPlace:: withdrawA

Root + Impact

Description

The bidBeastMarketPlace:: withdrawAllFailedCredits function is intended to allow users to withdraw their funds when refund transfers fail. However, the function takes an arbitrary _receiver parameter to fetch the withdrawal amount from the bidBeastMarketPlace:: mapping(address => uint256) public failedTransferCredits; mapping but then resets the mapping for msg.sender instead of _receiver.
This creates a mismatch between whose balance is reduced and who receives the funds.

As a result, any user can pass another user’s address (with failed credits) as _receiver and drain their funds.

//q? address is taken in inputs , amount is asked for reciver adn it is trasnferred to the msg.sender
function withdrawAllFailedCredits(address _receiver) external {
uint256 amount = failedTransferCredits[_receiver];
require(amount > 0, "No credits to withdraw");
failedTransferCredits[msg.sender] = 0;
(bool success, ) = payable(msg.sender).call{value: amount}("");
require(success, "Withdraw failed");
}

Risk

Likelihood:

Critical fund loss: Attackers can withdraw other users’ failed refunds, resulting in theft of protocol/user funds.

Protocol insolvency: Malicious actors can continuously exploit this function until all stored failed credits are drained.

Breaks trust in the auction system: Honest bidders will lose their refunds, making the marketplace unusable.

Impact:

Critical fund loss: Attackers can withdraw other users’ failed refunds, resulting in theft of protocol/user funds.

Protocol insolvency: Malicious actors can continuously exploit this function until all stored failed credits are drained.

Breaks trust in the auction system: Honest bidders will lose their refunds, making the marketplace unusable.

Proof of Concept

Assume the following state in the mapping:

failedTransferCredits[Bidder1] = 1 ETH
failedTransferCredits[Bidder2] = 2 ETH

Bidder1 calls:

failedTransferCredits[Bidder2] = 2 ETH

so msg.sender is bidder1 with less bid(1 ether)

and _reciever is bidder2 with higher bid (2 ether),

Execution flow:

`amount = failedTransferCredits[Bidder2] → 2 ETH`
`failedTransferCredits[msg.sender] = 0 → clears Bidder1’s slot, not Bidder2’s`

Transfers 2 ETH to Bidder1

End state:

failedTransferCredits[Bidder2] still 2 ETH

But Bidder1 already stole the 2 ETH

This can be repeated indefinitely by calling again with Bidder2’s address and drain the protocol funds

Recommended Mitigation

Update the bidBeastMarketPlace:: withdrawAllFailedCredits function to ensure the caller can only withdraw their own failed credits. Remove the _receiver parameter and enforce msg.sender as the only source of withdrawal:

Use msg.sender only and remove _reciever input

function withdrawAllFailedCredits() external {
uint256 amount = failedTransferCredits[msg.sender];
require(amount > 0, "No credits to withdraw");
failedTransferCredits[msg.sender] = 0;
(bool success, ) = payable(msg.sender).call{value: amount}("");
require(success, "Withdraw failed");
}
Updates

Lead Judging Commences

cryptoghost Lead Judge about 1 month ago
Submission Judgement Published
Validated
Assigned finding tags:

BidBeast Marketplace: Unrestricted FailedCredits Withdrawal

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.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.