Bid Beasts

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

User Can Steal Another User's Failed Transfer Credits

Root + Impact

Description

  • The

    withdrawAllFailedCredits function is intended to let users claim funds from payouts that failed to be sent to them directly. However, the function contains a critical flaw where it uses a

    _receiver address to determine the amount to withdraw but uses msg.sender for the actual payment and balance update. This mismatch allows any user to drain the failedTransferCredits of any other user. An attacker (Attacker) can call withdrawAllFailedCredits with the address of a victim (Victim) who has an available credit balance. The function will correctly read the Victim's balance but will then send that amount of ETH to the Attacker (msg.sender).

// Root cause in the codebase with @> marks to highlight the relevant section
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:

  • This vulnerability occurs whenever a user's payout fails and a credit is logged to their address.

  • An attacker calls the withdrawAllFailedCredits function, passing the victim's address as the _receiver argument.

Impact:

  • Attackers can directly steal the full amount of pending withdrawal credits from any other user in the system.

  • This compromises the integrity of the contract's accounting and leads to a direct, irreversible loss of user funds.

Proof of Concept

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");
}

Recommended Mitigation

- function withdrawAllFailedCredits(address _receiver) external {
- uint256 amount = failedTransferCredits[_receiver];
+ 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 2 months 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.

Give us feedback!