A critical vulnerability has been identified in the withdraw()
function of the auction contract, allowing users to exploit the system by withdrawing the same amount repeatedly, leading to a complete draining of the protocol's ERC20 token balance. The root cause lies in the failure to update the user's balance after withdrawal, enabling them to call the function multiple times and receive the same amount indefinitely.
The withdraw()
function does not properly update the user's bid balance after they withdraw their tokens. Specifically, the balance is not reset to zero after a withdrawal is executed, allowing the user to call the function repeatedly and withdraw the same amount multiple times.
Here, the user's bid balance (amount
) is read, and the transfer is processed, but there is no code that resets the user's balance to zero after the withdrawal, creating a loophole for repeated withdrawals.
Place a bid in the auction.
Example: User A places a bid of 200 tokens.
Call the withdraw()
function after the auction ends.
User A receives their 200 tokens back as expected.
Call the withdraw()
function again.
The same 200 tokens are transferred again without any restrictions, as the user's balance was never updated to zero.
Repeat Step 3 to drain the entire balance of the contract.
Unlimited Token Withdrawal:
Any user who has previously bid can exploit this vulnerability to repeatedly withdraw their bid amount, draining the protocol's funds.
Complete Depletion of Contract's ERC20 Balance:
Since user balances are not updated after withdrawal, malicious actors can keep withdrawing tokens, leading to a loss of all funds stored in the contract.
Protocol Collapse:
If exploited, the contract will lose all liquidity, rendering the auction system dysfunctional and undermining user trust.
To fix this issue, the user's balance should be updated to zero immediately after they withdraw their tokens. This prevents repeated withdrawals and ensures the balance is correctly tracked.
By adding self.bid_values.entry(caller).write(0);
, the user's balance is reset to zero after a successful withdrawal, eliminating the potential for further withdrawals of the same amount.
The `withdraw` function doesn't reset the `bid_values` to 0 after the withdraw. That means the bidder can call multiple time the `withdraw` function and receive the whole balance of the protocol.
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.