withdrawAllFailedCredits allows anyone to drain users’ credits, risking significant contract fundsThe contract implements a pull mechanism to handle failed Ether transfers by crediting the amount to the user's account, which they can later withdraw using the BidBeastsNFTMarketPlace::withdrawAllFailedCredits function.
The intention was good, but the implementation was flawed a bit, leading to a devastating vulnerability. The withdrawAllFailedCredits function lacks any access control, meaning anyone can call this function to withdraw the failed transfer credits of any user. All one has to do is provide the target user's address as the _receiver parameter.
The surprising part is, it doesn't just drain the credits of the _receiver, but also allows withdrawing again and again if the contract has enough balance. This is because the function sets the failedTransferCredits value of msg.sender to 0, not _receiver.
Likelihood: High
Any caller can exploit this by targeting any address with a non-zero failedTransferCredits
Impact: High
Financial Loss: Unauthorised withdrawal of users’ failed transfer credits.
Contract Balance Drain: Repeated withdrawals can deplete the contract’s balance, affecting all users.
First, take a look at the already implemented RejectEther contract in the test file at line 9. This contract is used to simulate a user who rejects incoming Ether transfers, causing the transfer to fail and credits to be recorded. We will be using it in our PoC.
Next, add the following test test_UnauthorizedCreditWithdrawal in the test file:
Run the above test using the command:
The output we get:
The withdrawAllFailedCredits function should be restricted so that only the owner of the credits (i.e., msg.sender) can withdraw their own credits. This can be done by removing the _receiver parameter and using msg.sender directly. Optionally, add an event (e.g., CreditsWithdrawn(address, uint256)) for transparency.
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.