WP Customer Reviews <= 3.7.5 - Reflected Cross-Site Scripting via 'wpcr3_fname' Parameter
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:NTechnical Details
<=3.7.5What Changed in the Fix
Changes introduced in v3.7.6
Source Code
WordPress.org SVN# 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
valueattribute of an<input>field, typically the "Name" or "First Name" field in the review submission form. - Preconditions:
- The plugin must be active.
- At least one page must have the
[WPCR_INSERT]shortcode. - The plugin settings must allow the "Name" field to be displayed (default behavior).
3. Code Flow
- Entry Point: A user sends a GET request to a page containing the review form with the query parameter
wpcr3_fname. - Initialization: The plugin executes
WPCustomerReviews3::init()(hooked toinit). - Parameter Parsing:
init()callsWPCustomerReviews3::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.
- Shortcode Processing: When the page content is rendered, the
[WPCR_INSERT]shortcode is triggered. - Form Rendering: The shortcode handler (likely
frontend_review_formlogic) retrieves the value from$this->p->wpcr3_fname. - Sink: The value is echoed into the template:
Note: Source files suggest Goatee templates are used, but the underlying issue remains the lack of<input type="text" name="wpcr3_fname" id="wpcr3_fname" value="<?php echo $this->p->wpcr3_fname; ?>" ... />esc_attr()on the variable being injected into thevalueattribute.
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:
- Navigate to the page containing the
[WPCR_INSERT]shortcode. - Use
browser_evalto check for localized script data. - The plugin localizes data under the object
wpcr3_dataor similar (inferred fromwpcr3prefix).
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
- Identify/Create Target Page: Create a page with the
[WPCR_INSERT]shortcode to ensure the review form is present. - 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)>.
- The target is an attribute:
- Execute Request: Use the
http_requesttool to perform a GET request to the target page with the malicious parameter. - Analyze Response: Verify that the HTML response contains the unescaped payload within the input field.
6. Test Data Setup
- Activate Plugin: Ensure
wp-customer-reviewsis installed and active. - Create Vulnerable Page:
wp post create --post_type=page --post_title="Leave a Review" --post_status=publish --post_content='[WPCR_INSERT]' - 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
- 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 - Examine Source: Search for the
id="wpcr3_fname"element and check itsvalueattribute. - Bypass Check: If the string is empty, it means
isXssAttemptcaught 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:
- POST Reflection: Submit a POST request to the same URL with
wpcr3_fnamein the body.Content-Type: application/x-www-form-urlencodedBody: wpcr3_fname="><script>alert(1)</script>&wpcr3_submit=1
- Template Bypass: Check other fields. Parameters like
wpcr3_email,wpcr3_title, orwpcr3_websitelikely follow the same code path and may be equally vulnerable. - Case Sensitivity: Test if
isXssAttemptis case-sensitive:<ScRiPt>.
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
@@ -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.