Abandoned Cart Recovery for WooCommerce <= 1.1.10 - Unauthenticated Stored Cross-Site Scripting
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:NTechnical Details
<=1.1.10This 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_cartorwp_ajax_nopriv_vi_wacr_update_cart(inferred from typical VillaTheme plugin structures). - Vulnerable Parameters:
first_name,last_name,phone, oremail. - 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)
- Entry Point: An unauthenticated user visits the WooCommerce checkout page.
- JS Execution: The plugin's frontend script (
abandoned-cart-recovery-for-woocommerce-public.js) monitors input fields. - AJAX Trigger: When the user enters data, an AJAX request is sent to
admin-ajax.phpwith an action (e.g.,vi_wacr_save_cart). - Storage: The PHP handler (likely in
includes/frontend.phporincludes/data.php) receives thePOSTdata and uses$wpdb->insert()orupdate_option()to save it without callingsanitize_text_field(). - 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.
- Identify Script Localizer: Look for
wp_localize_scriptin the plugin source (likely inincludes/frontend.php).- Search Command:
grep -r "wp_localize_script" .
- Search Command:
- Target Variable: Identify the object name (e.g.,
vi_wacr_frontend_params) and the nonce key (e.g.,_vi_wacr_nonce). - 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_evalto extract the nonce:window.vi_wacr_frontend_params?._vi_wacr_nonce || window.vi_wacr_params?.nonce
- Create a WooCommerce product:
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:
(Note: Parameters names likeaction=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=[]vi_wacr_first_namemight 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
- Install WooCommerce: Ensure WooCommerce is installed and the setup wizard is bypassed.
- Create Product:
wp post create --post_type=product --post_title='Exploit Product' --post_status=publish. - Plugin Configuration: Ensure "Capture Abandoned Carts" is enabled.
- Check:
wp option get vi_wacr_params(or similar option).
- Check:
- Add to Cart: Navigate to the product page and click "Add to Cart" to ensure a session is active.
7. Expected Results
- The
http_requestshould return a success status (e.g.,{"status":"success"}or1). - When the administrator logs in and navigates to the Abandoned Cart Recovery menu, the browser should trigger the
alert("XSS_SUCCESS").
8. Verification Steps
- 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 viawp db tables).
- Command:
- Admin View Simulation: Use
browser_navigateas an admin to the abandoned cart list page:- URL:
http://localhost:8080/wp-admin/admin.php?page=vi-abandoned-cart-recovery(verify slug inadmin_menuregistration). - Check for the alert or the payload in the DOM.
- URL:
9. Alternative Approaches
- Payload Location: If
first_nameis sanitized, tryemailorphone. Some plugins store the entirecart_dataobject; 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 AJAXcart_dataparameter 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_requestincludes the cookies returned from the initial page visit.
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
@@ -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']); @@ -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.