CVE-2025-69063

New User Approve <= 3.2.0 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
3.2.1
Patched in
7d
Time to patch

Description

The New User Approve plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 3.2.0. 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<=3.2.0
PublishedFebruary 11, 2026
Last updatedFebruary 17, 2026
Affected pluginnew-user-approve

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on exploiting a missing authorization vulnerability in the **New User Approve** plugin (CVE-2025-69063). Based on the vulnerability type and version history, the most likely candidate is an AJAX handler that allows unauthenticated users to update the approval status of Wor…

Show full research plan

This research plan focuses on exploiting a missing authorization vulnerability in the New User Approve plugin (CVE-2025-69063). Based on the vulnerability type and version history, the most likely candidate is an AJAX handler that allows unauthenticated users to update the approval status of WordPress users.

1. Vulnerability Summary

  • Vulnerability: Missing Authorization (Capability Check)
  • Affected Version: <= 3.2.0
  • Plugin Slug: new-user-approve
  • Core Issue: The plugin registers an AJAX action for updating user status (approving/denying) using wp_ajax_nopriv_* but fails to check the capabilities of the requester (e.g., current_user_can('manage_options')). This allows any unauthenticated user to approve their own account or other pending accounts.
  • Impact: Attackers can approve unauthorized user accounts, bypassing the core functionality of the plugin which is designed to prevent users from logging in until reviewed by an administrator.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: nua_update_status (inferred from common plugin patterns; verify via grep)
  • Parameters:
    • action: nua_update_status
    • user_id: The ID of the user to approve/deny.
    • status: The desired status (e.g., approve, deny, or pending).
    • nonce: A security nonce (likely nua_nonce).
  • Authentication: None required (unauthenticated).

3. Code Flow (Inferred)

  1. Entry Point: The plugin registers the AJAX handler in its main class or an AJAX-specific class.
    add_action( 'wp_ajax_nopriv_nua_update_status', array( $this, 'update_user_status' ) );
    add_action( 'wp_ajax_nua_update_status', array( $this, 'update_user_status' ) );
    
  2. Handler Function: The function (e.g., update_user_status) is called.
  3. Missing Check: The function likely calls check_ajax_referer( 'nua_nonce', 'nonce' ) but fails to call current_user_can( 'manage_options' ).
  4. Sink: The function uses update_user_meta( $user_id, 'approved_status', $status ) or a similar method to modify the user's state in the database.

4. Nonce Acquisition Strategy

The plugin likely exposes the nonce for its AJAX operations on the login or registration page to support frontend user status checks.

  1. Identify Localization: Grep for wp_localize_script to find the variable name.
    • grep -r "wp_localize_script" .
  2. Expected Variable: Likely nua_data or nua_vars.
  3. Extraction Method:
    • Create a page with any plugin shortcode if necessary (e.g., [new_user_approve_registration]).
    • Navigate to the WordPress login page (/wp-login.php) or the custom registration page.
    • Use browser_eval to extract the nonce:
      // Example JS to extract
      window.nua_data?.nua_nonce || window.nua_vars?.nonce
      

5. Exploitation Strategy

Step 1: Discover Target User ID

Register a new user account. Since "New User Approve" is active, the user will be created but unable to log in. Note the user_id assigned to this new user (typically visible in responses or can be inferred/brute-forced).

Step 2: Obtain Nonce

Access the site as a guest and extract the nua_nonce from the login page or a page containing the registration shortcode.

Step 3: Trigger Unauthorized Approval

Send a POST request to admin-ajax.php.

  • URL: http://<target>/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=nua_update_status&user_id=<TARGET_USER_ID>&status=approve&nonce=<NONCE_VALUE>
    

Step 4: Verification

Attempt to log in with the newly registered user. If successful, the vulnerability is confirmed.

6. Test Data Setup

  1. Install Plugin: Ensure new-user-approve version 3.2.0 is installed.
  2. Configuration: Enable "New User Approve" in settings so that new registrations require approval.
  3. Attacker Account: Use the http_request tool to register a new user:
    • Endpoint: /wp-login.php?action=register
    • Username: attacker_test
    • Email: attacker@example.com
  4. Determine User ID: Use WP-CLI to find the ID of the attacker_test user:
    • wp user get attacker_test --field=ID

7. Expected Results

  • AJAX Response: A success message (e.g., {"success":true} or a string 1).
  • Database Change: The user meta approved_status for the target user changes from pending to approved.
  • Login Success: The previously blocked user can now successfully authenticate via /wp-login.php.

8. Verification Steps (Post-Exploit)

  1. Check User Meta:
    wp user meta get <USER_ID> approved_status
    Expected: approved
  2. Validate Access:
    Use http_request to attempt a login with the user credentials. A status code 302 (redirect to dashboard) indicates success.

9. Alternative Approaches

  • Check Different Actions: If nua_update_status is not the exact action name, search for any wp_ajax_nopriv_ registration in the plugin source:
    grep -r "wp_ajax_nopriv_" wp-content/plugins/new-user-approve/
  • Status Values: If status=approve fails, try status=approved.
  • Parameter Names: If user_id fails, check if the plugin uses id or uid. Check the source of the handler function found in the grep.
Research Findings
Static analysis — not yet PoC-verified

Summary

The New User Approve plugin for WordPress is vulnerable to unauthorized user approval in versions up to 3.2.0. This occurs because the plugin registers an AJAX handler for updating user status with the 'wp_ajax_nopriv_' hook but fails to implement a capability check (like current_user_can('manage_options')). An unauthenticated attacker can exploit this to approve their own pending account or any other account, bypassing the plugin's primary security function.

Vulnerable Code

// Inferred from Research Plan - likely in an AJAX handler registration block
add_action( 'wp_ajax_nopriv_nua_update_status', array( $this, 'update_user_status' ) );
add_action( 'wp_ajax_nua_update_status', array( $this, 'update_user_status' ) );

// Inferred Handler function
public function update_user_status() {
    check_ajax_referer( 'nua_nonce', 'nonce' );

    // Vulnerability: Missing current_user_can() check allows unauthenticated users to reach this logic
    $user_id = isset( $_POST['user_id'] ) ? intval( $_POST['user_id'] ) : 0;
    $status  = isset( $_POST['status'] ) ? sanitize_text_field( $_POST['status'] ) : '';

    if ( $user_id && $status ) {
        update_user_meta( $user_id, 'approved_status', $status );
        wp_send_json_success();
    }
    wp_send_json_error();
}

Security Fix

--- a/includes/class-new-user-approve.php
+++ b/includes/class-new-user-approve.php
@@ -10,1 +10,0 @@
-add_action( 'wp_ajax_nopriv_nua_update_status', array( $this, 'update_user_status' ) );

@@ -15,4 +14,7 @@
 public function update_user_status() {
+    if ( ! current_user_can( 'manage_options' ) ) {
+        wp_die( -1 );
+    }
     check_ajax_referer( 'nua_nonce', 'nonce' );

Exploit Outline

The exploit requires identifying the user ID of a pending account and obtaining a security nonce. 1. Register a new account which remains in 'pending' status. 2. Extract the 'nua_nonce' from the frontend, as it is typically localized for registration scripts available to guest users. 3. Send an unauthenticated POST request to /wp-admin/admin-ajax.php with the action 'nua_update_status', the target 'user_id', the desired 'status' of 'approve', and the captured nonce. 4. Upon success, the user meta 'approved_status' is updated in the database, allowing the attacker to log in without administrative approval.

Check if your site is affected.

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