Critical Security Vulnerability: Money Creation Exploit in Wallet Transfer

Free plugin Unanswered

Critical Security Vulnerability: Money Creation Exploit in Wallet Transfer

Started by rjrefat TeraWallet – Best WooCommerce Wallet System 2 months, 1 week ago
Tagged:

Conversation

1 posts · 1 voices
Viewing 1 post (of 1 total)
  • February 7, 2026 at 7:34 am #8750

    Dear Developer Team,

    I am writing to report a Critical Severity vulnerability in the do_wallet_transfer function of the Woo Wallet / TeraWallet plugin.

    This flaw allows malicious users to create money out of thin air by exploiting a “Credit-First” logic flaw combined with a Race Condition. I have confirmed this exploit on my production site where a user successfully transferred funds they did not have, inflating the total money supply in the system.

    1. The Logic Flaw (Root Cause)
    File: includes/class-woo-wallet-frontend.php Function: do_wallet_transfer()

    The vulnerability exists because the code credits the receiver before it successfully debits the sender.

    Current Vulnerable Logic:

    CREDIT the Receiver (woo_wallet()->wallet->credit).

    IF Credit is successful -> DEBIT the Sender.

    The Risk: If the Debit fails (e.g., due to low balance, database error, or a race condition lock), the system does not rollback the Credit. The receiver keeps the money, but the sender is never charged.

    2. Forensic Evidence (Database Logs)
    Here is a captured log from my database showing the attack in progress. A user sent 5 concurrent requests.

    Observed Behavior:

    Transaction #35 (Debit): The sender was correctly charged once ($0.20).

    Transaction #34, 36, 37, 38, 39 (Credit): The receiver was credited 5 times ($0.20 x 5 = $1.00).

    The Log Data:

    Plaintext

    ID | User | Type | Amount | Balance | Details
    —|——|——–|——–|———|——————————————
    34 | 297 | credit | 0.20 | 0.20 | Gift from User 295 (Exploit Success #1)
    35 | 295 | debit | 0.20 | 0.19 | Wallet funds transfer (Legit Deduct)
    36 | 297 | credit | 0.20 | 0.40 | Gift from User 295 (Exploit Success #2)
    37 | 297 | credit | 0.20 | 0.60 | Gift from User 295 (Exploit Success #3)
    38 | 297 | credit | 0.20 | 0.80 | Gift from User 295 (Exploit Success #4)
    39 | 297 | credit | 0.20 | 1.00 | Gift from User 295 (Exploit Success #5)
    Result: The sender spent $0.20, but the receiver got $1.00. The system lost $0.80.

    3. The Exploit Scenario (How they did it)
    Setup: The attacker uses a script (e.g., Python) to send 5 simultaneous HTTP POST requests to the “Wallet Transfer” endpoint.

    Execution: All 5 requests hit the server at the exact same millisecond.

    The Race:

    All 5 requests execute woo_wallet()->wallet->credit(…) successfully because there are no checks preventing incoming money.

    The system then tries to execute woo_wallet()->wallet->debit(…).

    The Failure:

    Only 1 request succeeds in debiting the user (locking the row).

    The other 4 requests fail the debit (because the balance is now too low or the database is locked).

    Crucial Error: The code does not check if the debit failed. It has already credited the receiver, so the money is permanently duplicated.

    4. Required Fix (Debit First Pattern)
    The logic must be reversed. You must successfully debit the sender before you credit the receiver.

    Corrected Logic Flow:

    DEBIT Sender.

    IF Debit is Successful -> CREDIT Receiver.

    ELSE (Debit Failed) -> Stop and Show Error.

    Patch Suggestion (includes/class-woo-wallet-frontend.php):

    PHP

    // … Inside do_wallet_transfer() …

    // 1. Perform Debit FIRST
    $debit_transaction_id = woo_wallet()->wallet->debit( get_current_user_id(), $debit_amount, $debit_note );

    if ( $debit_transaction_id ) {
    // 2. Debit Succeeded, NOW Credit the Receiver
    $credit_transaction_id = woo_wallet()->wallet->credit( $whom->ID, $credit_amount, $credit_note );

    if ( $credit_transaction_id ) {
    // Success: Log fees and hooks
    update_wallet_transaction_meta( $debit_transaction_id, ‘_wallet_transfer_charge’, $transfer_charge, get_current_user_id() );
    do_action( ‘woo_wallet_transfer_amount_debited’, $debit_transaction_id, get_current_user_id(), $whom->ID );
    do_action( ‘woo_wallet_transfer_amount_credited’, $credit_transaction_id, $whom->ID, get_current_user_id() );

    $response = array(
    ‘is_valid’ => true,
    ‘message’ => __( ‘Amount transferred successfully!’, ‘woo-wallet’ ),
    );
    } else {
    // Edge Case: Debit worked, but Credit failed. REFUND the sender immediately.
    woo_wallet()->wallet->credit( get_current_user_id(), $debit_amount, ‘Refund for failed transfer’ );
    $response = array( ‘is_valid’ => false, ‘message’ => __( ‘Transfer failed. Please try again.’, ‘woo-wallet’ ) );
    }
    } else {
    // Debit Failed (Insufficient funds or Race Condition). Do NOT credit receiver.
    $response = array(
    ‘is_valid’ => false,
    ‘message’ => __( ‘Transfer failed. Insufficient funds.’, ‘woo-wallet’ ),
    );
    }
    Please prioritize this fix in the next update, as this vulnerability directly impacts financial data integrity.

    Regards, Refat

Viewing 1 post (of 1 total)

Post a reply

Paste the exact error, your WooCommerce + WordPress versions, and any relevant steps. Screenshots help.

Sign in to reply

You must be logged in to reply to this topic.

Still stuck?

Three fast ways to keep moving if the thread above didn't resolve it.