CVE-2025-14452

WP Customer Reviews <= 3.7.5 - Reflected Cross-Site Scripting via 'wpcr3_fname' Parameter

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

Description

The WP Customer Reviews plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the 'wpcr3_fname' parameter in all versions up to, and including, 3.7.5 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link.

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<=3.7.5
PublishedFebruary 18, 2026
Last updatedFebruary 19, 2026
Affected pluginwp-customer-reviews

What Changed in the Fix

Changes introduced in v3.7.6

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2025-14452 - WP Customer Reviews Reflected XSS ## 1. Vulnerability Summary The **WP Customer Reviews** plugin (v3.7.5 and below) is vulnerable to **Reflected Cross-Site Scripting (XSS)** via the `wpcr3_fname` parameter. The vulnerability exists because the plugin accepts user-s…

Show full research plan

Research Plan: CVE-2025-14452 - WP Customer Reviews Reflected XSS

1. Vulnerability Summary

The WP Customer Reviews plugin (v3.7.5 and below) is vulnerable to Reflected Cross-Site Scripting (XSS) via the wpcr3_fname parameter. The vulnerability exists because the plugin accepts user-supplied input through GET or POST requests, stores it in a class property ($this->p), and subsequently reflects that value into the HTML of the review form without adequate sanitization or output escaping (e.g., esc_attr).

In wp-customer-reviews-3.php, the method make_p_obj() is responsible for parsing request parameters. It uses a custom isXssAttempt() function to perform basic filtering, which is evidently insufficient. When a page containing the review form shortcode is rendered, the plugin populates the form fields with values from $this->p to preserve user input (a common "sticky form" feature), leading to XSS if a malicious payload is provided.

2. Attack Vector Analysis

  • Endpoint: Any WordPress page or post containing the [WPCR_INSERT] shortcode.
  • Vulnerable Parameter: wpcr3_fname (can be passed via GET or POST).
  • Authentication: Unauthenticated (PR:N).
  • Payload Context: The payload is reflected into the value attribute of an <input> field, typically the "Name" or "First Name" field in the review submission form.
  • Preconditions:
    1. The plugin must be active.
    2. At least one page must have the [WPCR_INSERT] shortcode.
    3. The plugin settings must allow the "Name" field to be displayed (default behavior).

3. Code Flow

  1. Entry Point: A user sends a GET request to a page containing the review form with the query parameter wpcr3_fname.
  2. Initialization: The plugin executes WPCustomerReviews3::init() (hooked to init).
  3. Parameter Parsing: init() calls WPCustomerReviews3::make_p_obj().
    • make_p_obj() iterates through $_GET.
    • For $_GET['wpcr3_fname'], it calls $this->isXssAttempt($val).
    • If the check passes (or is bypassed), it assigns trim(stripslashes($val)) to $this->p->wpcr3_fname.
  4. Shortcode Processing: When the page content is rendered, the [WPCR_INSERT] shortcode is triggered.
  5. Form Rendering: The shortcode handler (likely frontend_review_form logic) retrieves the value from $this->p->wpcr3_fname.
  6. Sink: The value is echoed into the template:
    <input type="text" name="wpcr3_fname" id="wpcr3_fname" value="<?php echo $this->p->wpcr3_fname; ?>" ... />
    
    Note: Source files suggest Goatee templates are used, but the underlying issue remains the lack of esc_attr() on the variable being injected into the value attribute.

4. Nonce Acquisition Strategy

Reflected XSS on page load via query parameters usually does not require a nonce in WordPress, as the goal is to reflect input into the initial HTML response. Nonces are typically used to protect state-changing actions (POST/AJAX).

However, if the plugin requires a nonce just to render the form (unlikely but possible), the strategy would be:

  1. Navigate to the page containing the [WPCR_INSERT] shortcode.
  2. Use browser_eval to check for localized script data.
  3. The plugin localizes data under the object wpcr3_data or similar (inferred from wpcr3 prefix).

Confirmed: For this specific reflected XSS via GET parameter reflection into a form field, no nonce is required to trigger the vulnerability.

5. Exploitation Strategy

  1. Identify/Create Target Page: Create a page with the [WPCR_INSERT] shortcode to ensure the review form is present.
  2. Construct Payload:
    • The target is an attribute: value="[PAYLOAD]".
    • Breakout payload: "><script>alert(window.origin)</script>
    • If isXssAttempt() blocks <script, use an event handler: "><img src=x onerror=alert(1)>.
  3. Execute Request: Use the http_request tool to perform a GET request to the target page with the malicious parameter.
  4. Analyze Response: Verify that the HTML response contains the unescaped payload within the input field.

6. Test Data Setup

  1. Activate Plugin: Ensure wp-customer-reviews is installed and active.
  2. Create Vulnerable Page:
    wp post create --post_type=page --post_title="Leave a Review" --post_status=publish --post_content='[WPCR_INSERT]'
    
  3. Configure Plugin (Optional): Ensure the "Name" field is enabled in the plugin settings (it is enabled by default).

7. Expected Results

  • HTTP Response: The response body should contain the literal string value=""><script>alert(window.origin)</script>".
  • Browser Execution: If viewed in a browser, an alert box with the site's origin should appear.

8. Verification Steps

  1. Confirm Reflection via HTTP:
    # Use the PoC agent's http_request tool
    # URL: http://localhost:8080/leave-a-review/?wpcr3_fname=%22%3E%3Cscript%3Ealert(1)%3C/script%3E
    
  2. Examine Source: Search for the id="wpcr3_fname" element and check its value attribute.
  3. Bypass Check: If the string is empty, it means isXssAttempt caught the payload. Try an alternative:
    • wpcr3_fname=%22+onmouseover%3D%22alert(1)%22+style%3D%22display%3Ablock%3Bwidth%3A1000px%3Bheight%3A1000px%3B%22

9. Alternative Approaches

If GET parameters are filtered more strictly than POST parameters:

  1. POST Reflection: Submit a POST request to the same URL with wpcr3_fname in the body.
    • Content-Type: application/x-www-form-urlencoded
    • Body: wpcr3_fname="><script>alert(1)</script>&wpcr3_submit=1
  2. Template Bypass: Check other fields. Parameters like wpcr3_email, wpcr3_title, or wpcr3_website likely follow the same code path and may be equally vulnerable.
  3. Case Sensitivity: Test if isXssAttempt is case-sensitive: <ScRiPt>.
Research Findings
Static analysis — not yet PoC-verified

Summary

The WP Customer Reviews plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the 'wpcr3_fname' parameter due to insufficient input sanitization and output escaping. Unauthenticated attackers can exploit this by tricking a user into clicking a link that reflects a malicious payload into the value attribute of a form field on pages containing the review shortcode.

Vulnerable Code

// wp-customer-reviews-3.php lines 202-230
function make_p_obj() {
    $this->p = new stdClass();

    foreach ($_GET as $c => $val) {
            if (is_array($val)) {
                    foreach ($val as $k => $v) {
                        if ($this->isXssAttempt($v)) {
                            $val[$k] = '';
                        }
                    }

                    $this->p->$c = $val;
            } else {
                    if ($this->isXssAttempt($val)) {
                        $val = '';
                    }

                    $this->p->$c = trim(stripslashes($val));
            }
    }

    foreach ($_POST as $c => $val) {
            if (is_array($val)) {
                    foreach ($val as $k => $v) {
                        if ($this->isXssAttempt($v)) {
                            $val[$k] = '';
                        }
                    }

                    $this->p->$c = $val;
                } else {
                    if ($this->isXssAttempt($val)) {
                        $val = '';
                    }

                    $this->p->$c = trim(stripslashes($val));
                }
            }

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/wp-customer-reviews/3.7.5/wp-customer-reviews-3.php /home/deploy/wp-safety.org/data/plugin-versions/wp-customer-reviews/3.7.6/wp-customer-reviews-3.php
--- /home/deploy/wp-safety.org/data/plugin-versions/wp-customer-reviews/3.7.5/wp-customer-reviews-3.php	2025-12-11 20:13:22.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wp-customer-reviews/3.7.6/wp-customer-reviews-3.php	2025-12-11 22:34:56.000000000 +0000
@@ -3,7 +3,7 @@
  * Plugin Name: WP Customer Reviews
  * Plugin URI: https://wordpress.org/plugins/wp-customer-reviews/
  * Description: Allows your visitors to leave business / product reviews. Testimonials are in Microdata / Microformat and may display star ratings in search results.
- * Version: 3.7.5
+ * Version: 3.7.6
  * Author: Aaron Queen
  * Author URI: https://wordpress.org/plugins/wp-customer-reviews/
  * Text Domain: wp-customer-reviews
@@ -199,44 +199,54 @@
         $this->options = get_option($this->options_name);
     }
 
+		function sanitize_p_obj_array($valArr) {
+			foreach ($valArr as $k => $v) {
+				if (is_array($v)) {
+					$valArr[$k] = $this->sanitize_p_obj_array($v);
+					continue;
+				}
+
+				if ($this->isXssAttempt($v)) {
+					$valArr[$k] = '';
+				}
+			}
+
+			return $valArr;
+		}
+
+		function sanitize_p_obj() {
+			foreach ($this->p as $c => $val) {
+				if (is_array($val)) {
+					$this->p->$c = $this->sanitize_p_obj_array($val);
+					continue;
+				}
+
+				if ($this->isXssAttempt($val)) {
+					$this->p->$c = '';
+				}
+			}
+		}
+
 		function make_p_obj() {
 			$this->p = new stdClass();
 
 			foreach ($_GET as $c => $val) {
-					if (is_array($val)) {
-							foreach ($val as $k => $v) {
-								if ($this->isXssAttempt($v)) {
-									$val[$k] = '';
-								}
-							}
-
-							$this->p->$c = $val;
-					} else {
-							if ($this->isXssAttempt($val)) {
-								$val = '';
-							}
-
-							$this->p->$c = trim(stripslashes($val));
-					}
+				if (is_array($val)) {
+					$this->p->$c = $val;
+				} else {
+					$this->p->$c = trim(stripslashes($val));
+				}
 			}
 
 			foreach ($_POST as $c => $val) {
-					if (is_array($val)) {
-							foreach ($val as $k => $v) {
-								if ($this->isXssAttempt($v)) {
-									$val[$k] = '';
-								}
-							}
-
-							$this->p->$c = $val;
-						} else {
-							if ($this->isXssAttempt($val)) {
-								$val = '';
-							}
-
-							$this->p->$c = trim(stripslashes($val));
-						}
-					}
+				if (is_array($val)) {
+					$this->p->$c = $val;
+				} else {
+					$this->p->$c = trim(stripslashes($val));
+				}
+			}
+
+			$this->sanitize_p_obj();
 		}

Exploit Outline

1. Identify a WordPress page or post that contains the review form shortcode [WPCR_INSERT]. 2. Construct a malicious URL targeting this page by adding the query parameter 'wpcr3_fname'. 3. Use a payload designed to break out of an HTML attribute, such as "><script>alert(window.origin)</script> or an event handler like "><img src=x onerror=alert(1)> if <script> tags are caught by the weak isXssAttempt filter. 4. Persuade a user (especially an administrator) to visit the constructed URL. 5. Upon loading the page, the plugin will populate the 'Name' input field's value attribute with the unsanitized payload, causing the browser to execute the injected script.

Check if your site is affected.

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