CVE-2025-10679

ReviewX – WooCommerce Product Reviews with Multi-Criteria, Reminder Emails, Google Reviews, Schema & More <= 2.2.12 - Unauthenticated Limited Remote Code Execution

highImproper Control of Generation of Code ('Code Injection')
7.3
CVSS Score
7.3
CVSS Score
high
Severity
2.3.0
Patched in
1d
Time to patch

Description

The ReviewX – WooCommerce Product Reviews with Multi-Criteria, Reminder Emails, Google Reviews, Schema & More plugin for WordPress is vulnerable to arbitrary method calls in all versions up to, and including, 2.2.12. This is due to insufficient input validation in the bulkTenReviews function that allows user-controlled data to be passed directly to a variable function call mechanism. This makes it possible for unauthenticated attackers to call arbitrary PHP class methods that take no inputs or have default values, potentially leading to information disclosure or remote code execution depending on available methods and server configuration.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.2.12
PublishedMarch 22, 2026
Last updatedMarch 23, 2026
Affected pluginreviewx

What Changed in the Fix

Changes introduced in v2.3.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2025-10679 ReviewX Unauthenticated Limited RCE ## 1. Vulnerability Summary **ReviewX** (up to 2.2.12) contains a vulnerability in the `bulkTenReviews` function (likely located in a controller like `Rvx\Controllers\Admin\ReviewController` or a similar handler class). The functio…

Show full research plan

Research Plan: CVE-2025-10679 ReviewX Unauthenticated Limited RCE

1. Vulnerability Summary

ReviewX (up to 2.2.12) contains a vulnerability in the bulkTenReviews function (likely located in a controller like Rvx\Controllers\Admin\ReviewController or a similar handler class). The function accepts user-controlled input (e.g., via $_POST['method'] and potentially $_POST['class']) and passes it directly to a variable function call mechanism (e.g., $this->$method() or call_user_func([$class, $method])) without sufficient validation.

Because this function is registered as an unauthenticated AJAX action (wp_ajax_nopriv_rvx_bulk_ten_reviews), an unauthenticated attacker can call arbitrary PHP class methods that require no arguments or have default values. This can lead to information disclosure (if the method returns sensitive data that is then echoed) or remote code execution (if a dangerous gadget method is called).

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: rvx_bulk_ten_reviews (Inferred from function name bulkTenReviews)
  • Vulnerable Parameters: method (and potentially class, call, or callback)
  • Authentication: Unauthenticated (leveraging wp_ajax_nopriv_)
  • Preconditions:
    • The ReviewX plugin must be active.
    • WooCommerce must be active (as ReviewX is a WooCommerce extension).
    • A valid WordPress nonce for the action may be required if the developer included a check_ajax_referer call (though often these unauthenticated vulnerabilities lack one).

3. Code Flow

  1. Entry Point: An unauthenticated request is sent to admin-ajax.php with action=rvx_bulk_ten_reviews.
  2. Hook Execution: WordPress triggers the wp_ajax_nopriv_rvx_bulk_ten_reviews action, which calls the bulkTenReviews method.
  3. Vulnerable Sink:
    • The function retrieves a method name from the request: $method = $_POST['method'];
    • It performs a dynamic call: $this->$method(); OR (new $_POST['class'])->$_POST['method']();
  4. Execution: The specified method is executed on the server. If the method produces output (like phpinfo) or returns data that the bulkTenReviews function subsequently echoes, the attacker receives the information.

4. Nonce Acquisition Strategy

If the endpoint requires a nonce, ReviewX typically exposes it via wp_localize_script for the frontend "public" review scripts.

  1. Identify Script Handle: The plugin registers public scripts, often with the handle reviewx-public.
  2. Localization Key: Look for reviewx_ajax_obj in the page source.
  3. Shortcode Strategy:
    • Create a WooCommerce product or a page containing the ReviewX review section.
    • Use WP-CLI to create a dummy product if none exists:
      wp eval "if(!get_page_by_path('test-product', OBJECT, 'product')){ wc_create_product(['name' => 'Test Product', 'status' => 'publish']); }"
  4. Acquisition Steps:
    • Navigate to the product page.
    • Use browser_eval to extract the nonce:
      browser_eval("window.reviewx_ajax_obj?.nonce")
      
    • Verbatim variable name check: reviewx_ajax_obj. Key: nonce.

5. Exploitation Strategy

Step 1: Verify Unauthenticated Access and Discover Parameters

Test if the action exists and if it requires a nonce.

POST /wp-admin/admin-ajax.php
Content-Type: application/x-www-form-urlencoded

action=rvx_bulk_ten_reviews

Step 2: Extract Nonce (If Required)

If the response is -1 or 403, follow the Nonce Acquisition Strategy.

Step 3: Information Disclosure PoC

Attempt to call a method that returns a known value. Based on app/Api/BaseApi.php, the getIp method returns a static IP. If we can control the class, we target this.

POST /wp-admin/admin-ajax.php
Content-Type: application/x-www-form-urlencoded

action=rvx_bulk_ten_reviews&nonce=[NONCE]&class=Rvx\Api\BaseApi&method=getIp

Expected Response: 192.168.68.119:10013 (if echoed).

Step 4: Limited RCE PoC (phpinfo)

Attempt to trigger phpinfo() via a class that wraps it or through a direct callback if the sink is call_user_func.

POST /wp-admin/admin-ajax.php
Content-Type: application/x-www-form-urlencoded

action=rvx_bulk_ten_reviews&nonce=[NONCE]&method=phpinfo

6. Test Data Setup

  1. Activate Dependencies: Ensure WooCommerce is installed and active.
  2. Create Product:
    wp post create --post_type=product --post_title="Exploit Test" --post_status=publish --post_content="Review section here"
    
  3. ReviewX Configuration: Ensure at least one review criteria is set up (usually default).

7. Expected Results

  • Success: The HTTP response body contains the output of the called method (e.g., phpinfo table, specific strings from the plugin classes, or WooCommerce system info).
  • Vulnerability Confirmation: Receiving the return value of a method that is not intended to be called publicly (e.g.,
Research Findings
Static analysis — not yet PoC-verified

Summary

The ReviewX plugin for WordPress is vulnerable to unauthenticated limited remote code execution due to improper input validation in the `bulkTenReviews` function. Attackers can exploit this by supplying arbitrary class and method names via the `rvx_bulk_ten_reviews` AJAX action, which the server then executes without sufficient verification.

Vulnerable Code

/* Inferred from the 'rvx_bulk_ten_reviews' AJAX handler logic */

// The function retrieves a method name from the request:
$method = $_POST['method'];

// It performs a dynamic call:
$this->$method(); 
// OR 
(new $_POST['class'])->$_POST['method']();

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/reviewx/2.2.12/app/Api/BaseApi.php /home/deploy/wp-safety.org/data/plugin-versions/reviewx/2.3.0/app/Api/BaseApi.php
--- /home/deploy/wp-safety.org/data/plugin-versions/reviewx/2.2.12/app/Api/BaseApi.php	2025-10-15 13:32:48.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/reviewx/2.3.0/app/Api/BaseApi.php	2025-12-22 12:17:34.000000000 +0000
@@ -35,6 +35,6 @@
      */
     public function getDefaultHeaders() : array
     {
-        return ['Authorization' => 'Bearer ' . Helper::getAuthToken(), 'X-Auth-Token' => 'Bearer ' . Helper::getAuthToken(), 'Accept' => 'application/json', 'X-Domain' => Helper::getWpDomainNameOnly(), 'X-Theme' => wp_get_theme()->get('Name'), 'X-Site-Locale' => get_locale(), 'X-Request-Id' => \sha1(\time() . Client::getUid()), 'X-Wp-Version' => get_bloginfo("version"), 'X-Reviewx-Version' => RVX_VERSION, 'X-Environment' => Helper::plugin()->isProduction() ? 'production' : 'development'];
+        return ['Accept' => 'application/json', 'Authorization' => 'Bearer ' . Helper::getAuthToken(), 'X-Domain' => Helper::getWpDomainNameOnly(), 'X-Theme' => wp_get_theme()->get('Name'), 'X-Site-Locale' => get_locale(), 'X-Request-Id' => \sha1(\time() . Client::getUid()), 'X-Wp-Version' => get_bloginfo("version"), 'X-Reviewx-Version' => RVX_VERSION, 'X-Environment' => Helper::plugin()->isProduction() ? 'production' : 'development'];
     }
 }

Exploit Outline

1. Identify the unauthenticated AJAX endpoint at `/wp-admin/admin-ajax.php` using the action `rvx_bulk_ten_reviews`. 2. Locate a valid nonce if required by inspecting the frontend page source for the `reviewx_ajax_obj` object, which typically contains a `nonce` key. 3. Craft a POST request to the AJAX endpoint with the `action` parameter set to `rvx_bulk_ten_reviews`. 4. Include a `method` parameter (and optionally a `class` parameter if the sink supports it) containing the name of a PHP method to execute. 5. Target methods that require no arguments or have default values, such as `phpinfo`, or specific internal plugin methods that disclose sensitive environment configuration or site data.

Check if your site is affected.

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