Critical Security Vulnerability Report: Race Condition in Wallet Payment Logic

Viewing 1 post (of 1 total)
  • Author
    Posts
  • #8747
    rjrefat
    Participant

    Dear Developer Team,
    I am writing to report a critical vulnerability in the Woo Wallet plugin (specifically within includes/class-woo-wallet-wallet.php) that allows users to exploit a Race Condition to spend more funds than they possess.
    I have confirmed this exploit on my production site where a malicious bot successfully placed 5 simultaneous orders (totaling $11.50) while only having **$5.00** in their wallet. This resulted in financial loss (gift codes released) and corrupted ledger data.
    1. The Vulnerability (Technical Root Cause)
    The issue lies in the recode_transaction function. The logic follows a “Check-Then-Act” pattern without any database locking (Mutex).
    Vulnerable Code Flow:
    1. Read: get_wallet_balance() is called to retrieve the current balance.
    2. Check: A PHP check if ( $amount > $balance ) is performed.
    3. Write: If the check passes, $wpdb->insert records the debit.
    The Exploit:
    Because there is no GET_LOCK() or SELECT … FOR UPDATE, concurrent requests sent at the exact same millisecond all read the same initial balance before the first request has time to deduct the funds.
    2. Forensic Evidence (Database Logs)
    I have isolated the malicious transactions from my database. The following 4 debit transactions occurred at the exact same second for the same user.
    Critical Observation: Notice that the balance column (Resulting Balance) remains frozen at **$0.40** for all 4 transactions. This proves they all calculated the balance based on the same starting point ($2.70) simultaneously.
    Tx ID Type Amount Balance (Recorded) Date Details
    #24 debit $2.30 **$2.70** 2026-02-05 04:04:46 (Legitimate Transaction)
    #25 debit $2.30 **$0.40** 2026-02-05 04:36:33 Attack Request 1
    #26 debit $2.30 **$0.40** 2026-02-05 04:36:33 Attack Request 2
    #27 debit $2.30 **$0.40** 2026-02-05 04:36:33 Attack Request 3
    #28 debit $2.30 **$0.40** 2026-02-05 04:36:33 Attack Request 4
    Actual funds available: $2.70
    Total spent in 1 second: $9.20
    Result: The user successfully purchased 4 items they could not afford.
    3. Reproduction Steps (Proof of Concept)
    I reproduced this locally using a Python script with threading to synchronize 5 HTTP POST requests to /?wc-ajax=checkout.
    Scenario:
    • Wallet Balance: 50.00
    • Product Price: 50.00
    • Cart Quantity: 1
    • Attack: 5 Concurrent Threads
    Result:
    • 4 out of 5 orders were Successful (Status: Processing).
    • 1 order failed.
    • The wallet balance became desynced (showing positive balance in cache, but negative if summing the DB rows).
    4. Recommended Fix (Immediate Patch Required)
    To fix this, you must implement a Database Lock (Mutex) to serialize requests for the same user.
    Please update includes/class-woo-wallet-wallet.php to acquire a lock before reading the balance:
    PHP
    private function recode_transaction( $amount, $type, $details, $args = null ) {
    global $wpdb;

    // — SECURITY FIX: ACQUIRE LOCK —
    $lock_name = ‘woo_wallet_user_’ . $this->user_id;
    // Wait up to 5 seconds for the lock
    $is_locked = $wpdb->get_var( $wpdb->prepare( “SELECT GET_LOCK(%s, 5)”, $lock_name ) );

    if ( ! $is_locked ) {
    return false; // Prevent race condition collision
    }

    try {
    // … [Existing Code: Get Balance -> Check Funds -> Insert DB] …
    } finally {
    // — SECURITY FIX: RELEASE LOCK —
    $wpdb->query( $wpdb->prepare( “SELECT RELEASE_LOCK(%s)”, $lock_name ) );
    }
    }
    This ensures that Request #2 cannot read the balance until Request #1 has finished deducting the funds.
    Please let me know when a patch will be released, as this is currently affecting my production site.
    Regards,
    Refat

Viewing 1 post (of 1 total)
  • You must be logged in to reply to this topic.

Login

Register

A link to set a new password will be sent to your email address.

Your personal data will be used to support your experience throughout this website, to manage access to your account, and for other purposes described in our privacy policy.

WhatsApp