CVE-2026-1316

Customer Reviews for WooCommerce <= 5.97.0 - Unauthenticated Stored Cross-Site Scripting via media[].href Parameter

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

Description

The Customer Reviews for WooCommerce plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'media[].href' parameter in all versions up to, and including, 5.97.0 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers (if 'Enable for Guests' is enabled) 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<=5.97.0
PublishedFebruary 12, 2026
Last updatedFebruary 12, 2026

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan outlines the steps required to demonstrate the Stored Cross-Site Scripting (XSS) vulnerability in the "Customer Reviews for WooCommerce" plugin. ### 1. Vulnerability Summary The "Customer Reviews for WooCommerce" plugin fails to properly sanitize the `href` attribute within the `…

Show full research plan

This research plan outlines the steps required to demonstrate the Stored Cross-Site Scripting (XSS) vulnerability in the "Customer Reviews for WooCommerce" plugin.

1. Vulnerability Summary

The "Customer Reviews for WooCommerce" plugin fails to properly sanitize the href attribute within the media array parameter during review submissions. When a user (including unauthenticated guests, if enabled) submits a review with media attachments, the href parameter is stored in the database. Because this value is not validated or escaped using esc_url() upon storage or output, an attacker can inject malicious javascript: URIs or breakout of the HTML attribute context to execute arbitrary JavaScript when the review is viewed by an admin or other users.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: ivole_post_review (inferred based on plugin architecture for review submission)
  • Vulnerable Parameter: media[0][href] (an array parameter)
  • Authentication: Unauthenticated (requires ivole_enable_guest_reviews setting to be yes)
  • Precondition: The "Enable for Guests" option must be enabled in the plugin settings to allow unauthenticated exploitation.

3. Code Flow (Inferred)

  1. Entry Point: The plugin registers a wp_ajax_nopriv_ivole_post_review hook to handle review submissions from guests.
  2. Processing: The handler function (likely in includes/reviews/class-cr-reviews.php or similar) retrieves the media array from $_POST.
  3. Storage: The plugin iterates through the media items and saves the href values as comment meta or within a JSON-encoded array in the wp_comments table. It fails to use esc_url_raw() or a similar sanitization filter.
  4. Sink: When a user views the product page or an admin views the "Reviews" menu in the dashboard, the plugin retrieves the media data and renders an <a> or <img> tag using the raw href value without esc_url() or esc_attr().

4. Nonce Acquisition Strategy

The plugin typically uses wp_localize_script to pass a security nonce to the frontend review form.

  1. Shortcode Identification: The review form is rendered via the [cusrev_reviews_form] shortcode (or sometimes automatically on product pages).
  2. Page Creation:
    wp post create --post_type=page --post_title="Review Test" --post_status=publish --post_content='[cusrev_reviews_form]'
    
  3. Extraction:
    • Navigate to the newly created page.
    • The script data is usually stored in the ivole_ajax_object (or cr_ajax_object in newer versions) global JS variable.
    • Verification: Use browser_eval to find the nonce.
    // Check for common localization objects used by this plugin
    window.ivole_ajax_object?.ivole_post_review_nonce || window.cr_ajax_object?.nonce
    

5. Exploitation Strategy

Step 1: Configure Plugin Settings
Ensure guest reviews are enabled so the nopriv AJAX action is reachable.

wp option update ivole_enable_guest_reviews "yes"

Step 2: Obtain Nonce
Use the browser_navigate and browser_eval tools to grab the nonce from the page containing the shortcode.

Step 3: Submit Malicious Review
Send a POST request to admin-ajax.php with the XSS payload.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Parameters:
    • action: ivole_post_review
    • security: [NONCE_OBTAINED_IN_STEP_2]
    • comment_post_ID: 1 (or any valid product ID)
    • author: Attacker
    • email: attacker@example.com
    • comment: Great product!
    • rating: 5
    • media[0][type]: image
    • media[0][href]: javascript:alert(document.domain) (Payload A)
    • media[0][href]: "><img src=x onerror=alert(1)> (Payload B - if attribute breakout is possible)

Step 4: Trigger XSS
Navigate to the WordPress admin dashboard reviews section (/wp-admin/edit-comments.php) or the product page where the review was posted.

6. Test Data Setup

  1. Product: Ensure at least one WooCommerce product exists (ID 1).
  2. Settings:
    wp option update ivole_enable_guest_reviews "yes"
    # Ensure reviews are actually enabled in WooCommerce
    wp option update woocommerce_enable_reviews "yes"
    
  3. Form Page: Create the page for nonce extraction as described in Section 4.

7. Expected Results

  • The AJAX request should return a success status (likely {"code":1} or similar JSON).
  • The review should appear in the "Pending" or "Approved" comments list in the WordPress database.
  • When viewing the review in the admin dashboard, the media link should contain the malicious payload.
  • Clicking the media link or simply loading the page (if using Payload B) will execute the JavaScript.

8. Verification Steps

  1. Database Check: Verify the payload is stored in the database unsanitized.
    # Check comment meta (common storage for CR WooCommerce)
    wp db query "SELECT meta_value FROM wp_commentmeta WHERE meta_key = 'ivole_review_image' OR meta_key = 'cr_review_media'"
    
  2. HTML Response Check: Fetch the product page or admin comment page and check for the unescaped payload.
    # Use http_request to get the HTML of the product page
    # Search for the string "javascript:alert" or the injected img tag.
    

9. Alternative Approaches

  • Action String Variations: If ivole_post_review fails, check for cr_post_review or ivole_submit_review.
  • Parameter Structure: If media[0][href] does not work, try media_url[] or ivole_files[] based on observing the network traffic when submitting a legitimate review via the browser.
  • Bypass Nonce: Check if the security check is missing in the nopriv version of the handler. Some versions of this plugin historically had weak nonce enforcement for guest reviews.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Customer Reviews for WooCommerce plugin is vulnerable to unauthenticated Stored Cross-Site Scripting (XSS) due to a failure to sanitize the 'href' field within the media array during review submission. Attackers can inject 'javascript:' URIs that execute in the context of an administrator's browser when they view the review in the dashboard.

Vulnerable Code

// Inferred from plugin architecture: includes/reviews/class-cr-reviews.php

// During review submission handling
if ( isset( $_POST['media'] ) && is_array( $_POST['media'] ) ) {
    $media = $_POST['media'];
    // Vulnerable: Saving raw user input from the 'media' array without sanitization
    update_comment_meta( $comment_id, 'ivole_review_media', $media );
}

---

// During review display rendering (Admin or Frontend)
$media = get_comment_meta( $comment_id, 'ivole_review_media', true );
if ( ! empty( $media ) ) {
    foreach ( $media as $item ) {
        // Vulnerable: Outputting the 'href' value without esc_url() or esc_attr()
        echo '<a href="' . $item['href'] . '" target="_blank">View Media</a>';
    }
}

Security Fix

--- a/includes/reviews/class-cr-reviews.php
+++ b/includes/reviews/class-cr-reviews.php
@@ -120,7 +120,11 @@
 if ( isset( $_POST['media'] ) && is_array( $_POST['media'] ) ) {
-    $media = $_POST['media'];
+    $media = array();
+    foreach ( $_POST['media'] as $item ) {
+        $media[] = array(
+            'type' => sanitize_text_field( $item['type'] ),
+            'href' => esc_url_raw( $item['href'] )
+        );
+    }
     update_comment_meta( $comment_id, 'ivole_review_media', $media );
 }
 
@@ -350,5 +354,5 @@
 foreach ( $media as $item ) {
-    echo '<a href="' . $item['href'] . '" target="_blank">View Media</a>';
+    echo '<a href="' . esc_url( $item['href'] ) . '" target="_blank">View Media</a>';
 }

Exploit Outline

1. **Enable Guest Reviews**: Ensure the 'ivole_enable_guest_reviews' setting is set to 'yes' to allow unauthenticated submissions. 2. **Identify Target Product**: Find a valid WooCommerce product ID to post a review against. 3. **Retrieve AJAX Nonce**: Visit a page containing the '[cusrev_reviews_form]' shortcode. Extract the security nonce from the global JavaScript object (usually 'ivole_ajax_object' or 'cr_ajax_object'). 4. **Craft XSS Payload**: Prepare a malicious POST request to 'wp-admin/admin-ajax.php' using the 'ivole_post_review' action. 5. **Injection**: Set the 'media[0][href]' parameter to a JavaScript URI, such as 'javascript:alert(document.cookie)'. 6. **Trigger Execution**: Log into the WordPress dashboard as an administrator and navigate to the 'Reviews' or 'Comments' menu. The payload will execute when the malicious media link is rendered or clicked.

Check if your site is affected.

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