CVE-2026-3601

User Registration & Membership <= 5.1.4 - Missing Authorization to Authenticated (Contributor+) Limited Page Content Modification

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
5.1.5
Patched in
1d
Time to patch

Description

The User Registration & Membership plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the `embed_form_action()` function in all versions up to, and including, 5.1.4. This makes it possible for authenticated attackers, with Contributor-level access and above, to append shortcode content to arbitrary pages they do not own or have permission to edit.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=5.1.4
PublishedMay 4, 2026
Last updatedMay 5, 2026
Affected pluginuser-registration

What Changed in the Fix

Changes introduced in v5.1.5

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan targets **CVE-2026-3601** (likely a typo in the source for 2024 or 2025, but following the description provided), a missing authorization vulnerability in the **User Registration** plugin. This vulnerability allows an authenticated user with at least **Contributor** privileges to …

Show full research plan

This research plan targets CVE-2026-3601 (likely a typo in the source for 2024 or 2025, but following the description provided), a missing authorization vulnerability in the User Registration plugin. This vulnerability allows an authenticated user with at least Contributor privileges to append arbitrary shortcodes to pages or posts they do not own.


1. Vulnerability Summary

The vulnerability exists in the embed_form_action() function within the User Registration plugin (versions <= 5.1.4). The function is responsible for "embedding" a registration form into an existing WordPress post or page by appending the plugin's shortcode to the target post's content.

While the function likely implements a nonce check for CSRF protection, it fails to perform a capability check (e.g., current_user_can('edit_post', $post_id)) to ensure the authenticated user has permission to modify the target post_id. Consequently, any user who can access the WordPress admin (Contributor and above) can trigger this action against any page or post on the site.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: ur_embed_form (inferred from function name and plugin conventions)
  • Vulnerable Function: embed_form_action()
  • HTTP Method: POST
  • Payload Parameters:
    • action: ur_embed_form
    • post_id: The ID of the target page/post to be modified (e.g., an Administrator's page).
    • form_id: The ID of the User Registration form to embed.
    • security or nonce: The AJAX nonce for the action.
  • Authentication: Contributor-level session required.

3. Code Flow (Inferred)

  1. Registration: The plugin registers the AJAX action:
    add_action( 'wp_ajax_ur_embed_form', array( 'UR_Admin_Ajax', 'embed_form_action' ) );
  2. Entry: A Contributor sends a POST request to admin-ajax.php with action=ur_embed_form.
  3. Processing: embed_form_action() is called.
  4. Verification: The function checks the nonce provided in the security or nonce parameter.
  5. Vulnerability: The function retrieves post_id and form_id from $_POST. It proceeds to fetch the post via get_post($post_id) and updates its content using wp_update_post() or by appending the shortcode [user_registration_form id="123"] to the existing post_content.
  6. Missing Check: At no point does the function verify if the current user has the edit_post capability for the target post_id.

4. Nonce Acquisition Strategy

The "Embed" functionality is typically available in the User Registration "Forms" list in the admin dashboard. The plugin localizes its admin parameters into a JavaScript object.

  1. Create Contributor User: Log in as a Contributor.
  2. Identify Localization Key: The plugin typically uses ur_admin_params or user_registration_admin_params.
  3. Find Page with Scripts: Navigate to the User Registration forms list: /wp-admin/admin.php?page=user-registration.
  4. Extract Nonce:
    • Use browser_navigate to go to the forms list.
    • Use browser_eval to extract the nonce:
      browser_eval("ur_admin_params.ur_embed_form_nonce") (inferred key).

5. Exploitation Strategy

  1. Preparation:
    • Identify a target Page ID (owned by Admin) that is currently published.
    • Identify an existing User Registration Form ID.
  2. Authentication: Log in to the WordPress site as the Contributor user.
  3. Nonce Extraction: Access the User Registration admin page and extract the ur_embed_form nonce from the ur_admin_params JS object.
  4. Attack Request:
    Using the http_request tool, send the following:
    • URL: http://localhost:8080/wp-admin/admin-ajax.php
    • Method: POST
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body:
      action=ur_embed_form&post_id=[TARGET_PAGE_ID]&form_id=[FORM_ID]&security=[NONCE]
      
  5. Verify Modification: Check the content of the target page to see if the shortcode has been appended.

6. Test Data Setup

  1. Target Content: As Administrator, create a private or published page:
    wp post create --post_type=page --post_title="Admin Private Page" --post_content="Original Secret Content" --post_status=publish
    Note the returned ID as [TARGET_PAGE_ID].
  2. Registration Form: Ensure at least one registration form exists:
    wp post list --post_type=user_registration
    Note the ID as [FORM_ID]. If none exist, create one.
  3. Attacker Account: Create a Contributor user:
    wp user create attacker attacker@example.com --role=contributor --user_pass=password123

7. Expected Results

  • Response: The AJAX request should return a success status (e.g., {"success":true} or a string "success").
  • State Change: The page content of [TARGET_PAGE_ID] will be modified.
  • Effect: When viewing the page, the original content will be followed (or replaced) by the User Registration form shortcode: [user_registration_form id="[FORM_ID]"].

8. Verification Steps

  1. Check Post Content: Use WP-CLI to verify the modification:
    wp post get [TARGET_PAGE_ID] --field=post_content
  2. Verify Success: Confirm that the output contains the string [user_registration_form id=".
  3. Check Ownership: Verify the post is still owned by the Administrator, confirming the Contributor successfully edited content they do not own.

9. Alternative Approaches

  • Parameter Guessing: If security is not the correct parameter name, try nonce, _ajax_nonce, or ur_nonce.
  • Action Mapping: If ur_embed_form does not work, search the plugin's JS files (e.g., assets/js/admin/admin.js) for the string action: to find the exact AJAX action associated with the "Embed" button.
  • Form Creation: If no form exists, use wp post create --post_type=user_registration ... to create a dummy form to satisfy the form_id requirement.
Research Findings
Static analysis — not yet PoC-verified

Summary

The User Registration & Membership plugin for WordPress fails to perform a capability check in its `embed_form_action` AJAX function. This allows authenticated attackers with Contributor-level permissions or higher to append registration form shortcodes to any post or page on the site, potentially disrupting content or altering page layout.

Vulnerable Code

// File: includes/admin/class-ur-admin-ajax.php (inferred location)

public static function embed_form_action() {
    check_ajax_referer( 'ur_embed_form', 'security' );

    $post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
    $form_id = isset( $_POST['form_id'] ) ? absint( $_POST['form_id'] ) : 0;

    if ( $post_id && $form_id ) {
        $post = get_post( $post_id );
        $content = $post->post_content . '[user_registration_form id="' . $form_id . '"]';
        wp_update_post( array(
            'ID'           => $post_id,
            'post_content' => $content
        ) );
        wp_send_json_success();
    }
}

Security Fix

--- includes/admin/class-ur-admin-ajax.php
+++ includes/admin/class-ur-admin-ajax.php
@@ -10,6 +10,10 @@
 
 		$post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
 		$form_id = isset( $_POST['form_id'] ) ? absint( $_POST['form_id'] ) : 0;
+
+		if ( ! current_user_can( 'edit_post', $post_id ) ) {
+			wp_send_json_error( array( 'message' => __( 'You do not have permission to edit this post.', 'user-registration' ) ) );
+		}
 
 		if ( $post_id && $form_id ) {
 			$post = get_post( $post_id );

Exploit Outline

1. Authenticate as a user with Contributor-level access. 2. Navigate to the User Registration forms list in the WordPress admin dashboard to obtain a valid AJAX nonce from the localized `ur_admin_params` JavaScript object (specifically the `ur_embed_form_nonce` key). 3. Identify the ID of a target Page or Post (owned by an Administrator) and the ID of an existing User Registration form. 4. Send a POST request to `/wp-admin/admin-ajax.php` with the following parameters: `action=ur_embed_form`, `post_id=[TARGET_ID]`, `form_id=[FORM_ID]`, and `security=[NONCE]`. 5. The plugin will append the shortcode `[user_registration_form id="[FORM_ID]"]` to the end of the target post's content because it fails to verify if the requester has the `edit_post` capability for that specific `post_id`.

Check if your site is affected.

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