Failed ETH payments to users (e.g., seller proceeds or out‑bid refunds) are supposed to be credited in failedTransferCredits[recipient]. The intended withdrawal flow is that the same recipient later withdraws their own credits, and the contract zeroes that recipient’s balance before sending ETH to avoid double-withdrawals.
withdrawAllFailedCredits(address _receiver) reads the balance from failedTransferCredits[_receiver] but zeroes failedTransferCredits[msg.sender] and then transfers the funds to msg.sender. This lets an attacker withdraw someone else’s credits and, because the victim’s balance is never reduced, repeat the withdrawal indefinitely as long as the contract keeps receiving ETH (e.g., via bids, fees, or forced ether).
Likelihood:
This occurs whenever any failed payout credit exists—common in marketplaces because recipients can be contracts that reject ETH (e.g., no receive() or an intentional revert), creating credits for sellers or out‑bid bidders.
An attacker can call withdrawAllFailedCredits with any _receiver address holding credits; no authentication binds the withdrawal to the credited party.
Impact:
Direct theft of ETH held by the marketplace (seller proceeds, bidder refunds, accumulated fees) to the attacker’s address.
Repeated drains over time: because the victim’s credit is never decremented, the attacker can withdraw the same amount again whenever the contract balance is replenished (e.g., new bids, owner fee deposits, or forced ETH).
Bind withdrawal to msg.sender, clear the same account you read, and (defense‑in‑depth) add a reentrancy guard.
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.