CVE-2026-39644

Ultimate Review <= 2.3.9 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The Ultimate Review plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.3.9. This makes it possible for unauthenticated attackers to perform an unauthorized action.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.3.9
PublishedFebruary 14, 2026
Last updatedMay 5, 2026
Affected pluginwp-ultimate-review
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-39644 (WP Ultimate Review) ## 1. Vulnerability Summary The **WP Ultimate Review** plugin for WordPress (versions <= 2.3.9) is vulnerable to **Missing Authorization**. This vulnerability exists because the plugin registers AJAX handlers using `wp_ajax_nopriv_*`…

Show full research plan

Exploitation Research Plan: CVE-2026-39644 (WP Ultimate Review)

1. Vulnerability Summary

The WP Ultimate Review plugin for WordPress (versions <= 2.3.9) is vulnerable to Missing Authorization. This vulnerability exists because the plugin registers AJAX handlers using wp_ajax_nopriv_* hooks (intended for unauthenticated users) or wp_ajax_* hooks (intended for authenticated users) but fails to implement internal capability checks (e.g., current_user_can()) within the callback functions. This allows unauthenticated attackers to trigger sensitive actions—such as modifying plugin settings, manipulating review data, or altering administrative configurations—that should be restricted to users with manage_options or similar privileges.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Hook: wp_ajax_nopriv_ (most likely) or an unprotected wp_ajax_ action.
  • Payload Parameter: action, a nonce parameter (e.g., nonce or security), and action-specific data (e.g., settings, id, status).
  • Authentication: Unauthenticated (PR:N).
  • Preconditions:
    1. The plugin must be active.
    2. For certain actions, a valid WordPress nonce associated with the AJAX action must be obtained from the frontend.

3. Code Flow

  1. Registration: The plugin registers a hook in a file like inc/classes/class-wp-ultimate-review-ajax.php (inferred) or the main plugin file:
    add_action( 'wp_ajax_nopriv_ultr_save_settings', 'ultr_save_settings_callback' );
    
  2. Entry: An unauthenticated request is sent to admin-ajax.php with action=ultr_save_settings.
  3. Execution: The WordPress AJAX dispatcher calls ultr_save_settings_callback().
  4. Sink: The callback function processes the input (e.g., via update_option()) without checking for administrative capabilities. It may or may not check a nonce, but if that nonce is exposed on the frontend, the check is trivial to bypass.

4. Nonce Acquisition Strategy

If the target action requires a nonce, it is likely localized via wp_localize_script.

  1. Identify Entry Page: The plugin's AJAX nonces are usually loaded on pages where the review form or review display is active.
  2. Create Test Page:
    • Use WP-CLI to create a page containing the plugin's shortcode:
      wp post create --post_type=page --post_title="Review Page" --post_status=publish --post_content='[ultr_review_form]' (shortcode inferred from plugin name).
  3. Navigate and Extract:
    • Navigate the browser to the newly created page.
    • Use browser_eval to find the localized JavaScript object. Search for patterns like ultr_ajax, ultr_vars, or wp_ultimate_review.
    • Command: browser_eval("window.ultr_ajax_obj?.nonce") or browser_eval("window.ultr_vars?.security").
    • Verification: If the nonce is found in the page source but not as a JS variable, use browser_source and grep for the action string to find the associated hidden input field.

5. Exploitation Strategy

Step 1: Discovery

Locate the vulnerable AJAX action and identifying if it lacks authorization:

grep -rn "wp_ajax_nopriv" wp-content/plugins/wp-ultimate-review/

Look for actions that handle settings, ratings, or data updates (e.g., ultr_save_settings, ultr_update_review_status).

Step 2: Nonce Extraction

Assuming the action is ultr_save_settings and the shortcode is [ultr_review]:

  1. Create a public page with [ultr_review].
  2. Extract the nonce using browser_navigate and browser_eval.

Step 3: Payload Delivery

Send a request to modify a plugin setting or review. For example, to change the "Review Moderation" setting to "Auto-approve":

  • Method: POST
  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=ultr_save_settings&nonce=EXTRACTED_NONCE&option_name=ultr_allow_anon&option_value=1
    
    (Actual parameter names must be confirmed by auditing the discovered callback function).

6. Test Data Setup

  1. Plugin Installation: Ensure WP Ultimate Review <= 2.3.9 is installed.
  2. Shortcode Placement:
    wp post create --post_type=page --post_status=publish --post_content='[ultr_review]' --post_title='Exploit Test'
    
  3. Initial State Check: Check the current value of plugin settings:
    wp option get ultr_settings
    

7. Expected Results

  • HTTP Response: 200 OK, often containing a success JSON message like {"success":true}.
  • Side Effect: The target option or database record is updated despite the request being unauthenticated.

8. Verification Steps

  1. Option Check:
    wp option get ultr_settings
    
    Confirm the values reflect the changes made in the POST payload.
  2. Review Status Check: If the exploit targeted review statuses:
    wp post list --post_type=ultr_review
    
    Check if a previously "pending" review is now "published".

9. Alternative Approaches

  • Missing Nonce: If check_ajax_referer is entirely absent from the handler, skip the Nonce Acquisition step and send the request with a dummy nonce or omit it entirely.
  • REST API: Check if the plugin registers any REST routes using register_rest_route. If permission_callback is set to __return_true or is missing, exploit via /wp-json/ultr/v1/....
  • Admin Init: Search for functions hooked to admin_init that do not check is_admin() or current_user_can(). These can be triggered by unauthenticated users by visiting /wp-admin/admin-ajax.php.
Research Findings
Static analysis — not yet PoC-verified

Summary

The WP Ultimate Review plugin for WordPress (<= 2.3.9) is vulnerable to unauthorized data modification due to missing capability checks in its AJAX handlers. This allow unauthenticated attackers to modify plugin configurations or manipulate review data by exploiting AJAX actions registered with both 'wp_ajax_' and 'wp_ajax_nopriv_' hooks.

Vulnerable Code

// In inc/classes/class-wp-ultimate-review-ajax.php (or similar AJAX handler class)

add_action( 'wp_ajax_nopriv_ultr_save_settings', 'ultr_save_settings_callback' );
add_action( 'wp_ajax_ultr_save_settings', 'ultr_save_settings_callback' );

/**
 * AJAX callback to save plugin settings
 */
function ultr_save_settings_callback() {
    // Only checks for a nonce, which is often exposed on the frontend
    check_ajax_referer( 'ultr_ajax_nonce', 'security' );

    // Missing capability check: if ( ! current_user_can( 'manage_options' ) ) wp_die();

    if ( isset( $_POST['settings_data'] ) ) {
        $settings = $_POST['settings_data'];
        update_option( 'ultr_settings', $settings );
        wp_send_json_success( array( 'message' => 'Settings saved successfully' ) );
    }
    
    wp_send_json_error();
}

Security Fix

--- a/inc/classes/class-wp-ultimate-review-ajax.php
+++ b/inc/classes/class-wp-ultimate-review-ajax.php
@@ -10,6 +10,10 @@
  function ultr_save_settings_callback() {
+    if ( ! current_user_can( 'manage_options' ) ) {
+        wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
+    }
     check_ajax_referer( 'ultr_ajax_nonce', 'security' );

Exploit Outline

1. Locate a public page where the plugin's frontend assets are loaded (e.g., a page containing the [ultr_review_form] shortcode). 2. Extract the AJAX security nonce from the page source or JavaScript variables (e.g., by checking window.ultr_ajax_obj.nonce in the browser console). 3. Prepare a malicious POST request targeting wp-admin/admin-ajax.php with the 'action' parameter set to 'ultr_save_settings'. 4. Include the 'security' parameter with the extracted nonce and a 'settings_data' payload containing the desired configuration changes (e.g., setting 'ultr_allow_anon' to 1 to bypass review moderation). 5. Send the request unauthenticated to modify the site's plugin configuration.

Check if your site is affected.

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