UsersWP <= 1.2.58 - Authenticated (Subscriber+) Restricted Usermeta Modification via 'htmlvar' Parameter
Description
The UsersWP – Front-end login form, User Registration, User Profile & Members Directory plugin for WordPress is vulnerable to Improper Access Control in all versions up to, and including, 1.2.58 This is due to insufficient field-level permission validation in the upload_file_remove() AJAX handler where the $htmlvar parameter is not validated against a whitelist of allowed fields or checked against the field's for_admin_use property. This makes it possible for authenticated attackers, with subscriber-level access and above, to clear or reset any restricted usermeta column for their own user record, including fields marked as "For admin use only", bypassing intended field-level access restrictions.
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 v1.2.59
Source Code
WordPress.org SVN# Research Plan: CVE-2026-4977 - Authenticated Usermeta Modification in UsersWP ## 1. Vulnerability Summary The **UsersWP** plugin (<= 1.2.58) contains a flaw in its AJAX handling logic where an authenticated user (Subscriber level or higher) can clear or reset arbitrary `usermeta` fields for their…
Show full research plan
Research Plan: CVE-2026-4977 - Authenticated Usermeta Modification in UsersWP
1. Vulnerability Summary
The UsersWP plugin (<= 1.2.58) contains a flaw in its AJAX handling logic where an authenticated user (Subscriber level or higher) can clear or reset arbitrary usermeta fields for their own account.
The vulnerability exists in the uwp_upload_file_remove AJAX action (handled by UsersWP_Ajax::upload_file_remove()). The function accepts a user-controlled parameter htmlvar representing a metadata key. It fails to validate this key against an allowlist of permitted "file" fields or check if the field is flagged for administrative use only (for_admin_use). Consequently, an attacker can supply any meta key (e.g., wp_capabilities) to delete or reset its value.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
uwp_upload_file_remove - Vulnerable Parameter:
htmlvar(carries the targetusermetakey) - Authentication: Required (Subscriber level is sufficient)
- Nonce Requirement: Yes, the action requires a nonce typically localized as
uwp_localize_data.basicNonce. - Preconditions: The attacker must be logged in and able to access a page where the UsersWP scripts are enqueued to retrieve the nonce.
3. Code Flow
- Entry Point: The client sends a
POSTrequest toadmin-ajax.phpwithaction=uwp_upload_file_remove. - Hook Registration: In
includes/class-userswp.php, theUsersWP_Ajaxclass is initialized. This class registers the AJAX handler:add_action( 'wp_ajax_uwp_upload_file_remove', array( $this, 'upload_file_remove' ) ); - Handler Execution (
upload_file_remove):- It retrieves
security(nonce),htmlvar(meta key), anduid(user ID) from$_POST. - It verifies the nonce (likely against the action
uwp_basic_nonce). - It checks if the
uidmatches the current user or if the user has admin privileges. - Sink: It proceeds to call
update_user_meta($uid, $htmlvar, '')ordelete_user_meta($uid, $htmlvar)without verifying if$htmlvaris a restricted field.
- It retrieves
- Impact: The metadata field for the user is cleared.
4. Nonce Acquisition Strategy
The nonce is localized in the front-end using wp_localize_script under the object uwp_localize_data.
- Shortcode Identification: The plugin uses the
[uwp_profile]or[uwp_account]shortcodes to render user-facing forms whereusers-wp.jsis loaded. - Page Creation: Create a page containing the
[uwp_profile]shortcode. - Extraction:
- Navigate to the page as a logged-in Subscriber.
- Execute JavaScript via
browser_evalto retrieve the nonce:browser_eval("uwp_localize_data.basicNonce")
- JS Variable Verbatim:
uwp_localize_data.basicNonce(found inassets/js/users-wp.js).
5. Exploitation Strategy
The goal is to clear a restricted usermeta field, such as wp_capabilities (to remove the user's role) or a custom UsersWP field intended for admin use.
Step-by-Step Plan:
- Authentication: Log in as a Subscriber user.
- Nonce Retrieval:
- Navigate to
/profile-page/(created in setup). - Capture the value of
uwp_localize_data.basicNonce.
- Navigate to
- Target Selection:
- Target:
wp_capabilities(Standard WordPress restricted field). - Target:
uwp_admin_note(Inferred UsersWP meta field).
- Target:
- Exploit Request:
Send aPOSTrequest toadmin-ajax.php:- URL:
http://vulnerable-wp.local/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=uwp_upload_file_remove&htmlvar=wp_capabilities&uid=[CURRENT_USER_ID]&security=[NONCE]
- URL:
- Observation: The response should be a JSON object:
{"success": true}.
6. Test Data Setup
- Target User: A user with username
victim_suband rolesubscriber. - Landing Page:
wp post create --post_type=page --post_title="User Account" --post_status=publish --post_content='[uwp_account]' - Verification Meta: Ensure the user has a capability set.
wp user meta get [USER_ID] wp_capabilities
7. Expected Results
- The AJAX request returns
{"success": true}. - The
wp_capabilitiesmeta entry for thevictim_subuser is deleted or set to an empty string. - The user effectively loses their role and permissions on the site.
8. Verification Steps
- CLI Check:
Expected Output: Empty or error indicating the key does not exist.wp user meta get [USER_ID] wp_capabilities - Role Check:
Expected Output: Empty string.wp user get [USER_ID] --field=roles
9. Alternative Approaches
If wp_capabilities is protected by internal WordPress filters that UsersWP doesn't bypass, target UsersWP-specific fields created via the Form Builder (admin/settings/class-formbuilder.php).
- Create a custom field
uwp_verified_statusand set it to1for the user. - Use the exploit to clear
uwp_verified_status. - Verify the field is removed via
wp user meta get.
Summary
The UsersWP plugin for WordPress is vulnerable to unauthorized usermeta modification due to a lack of field-level validation in the 'uwp_upload_file_remove' AJAX handler. Authenticated attackers (Subscriber and above) can clear arbitrary usermeta fields for their own account, including restricted administrative fields like 'wp_capabilities', by manipulating the 'htmlvar' parameter.
Vulnerable Code
// assets/js/users-wp.js @ 1.2.58 $( '.uwp_upload_file_remove' ).on( 'click', function( event ) { event.preventDefault(); var htmlvar = $( this ).data( 'htmlvar' ); var uid = $( this ).data( 'uid' ); var data = { 'action': 'uwp_upload_file_remove', 'htmlvar': htmlvar, 'uid': uid, 'security': uwp_localize_data.basicNonce };
Security Fix
@@ -1818,7 +1818,7 @@ 'label' => __( 'Validation Pattern', 'userswp' ) . uwp_help_tip( __( 'Enter regex expression for HTML5 pattern validation.', 'userswp' ) ), 'type' => 'text', 'wrap_class' => uwp_advanced_toggle_class(), - 'value' => addslashes_gpc( $value ), // Keep slashes + 'value' => wp_slash( $value ), // Keep slashes ) ); @@ -106,8 +106,9 @@ $( '.uwp_upload_file_remove' ).on( 'click', function( event ) { event.preventDefault(); - var htmlvar = $( this ).data( 'htmlvar' ); - var uid = $( this ).data( 'uid' ); + var $this = $(this); + var htmlvar = $this.data( 'htmlvar' ); + var uid = $this.data( 'uid' ); var data = { 'action': 'uwp_upload_file_remove', @@ -116,17 +117,25 @@ 'security': uwp_localize_data.basicNonce }; + if ($this.closest("form").find('.uwp-field-error').length) { + $this.closest("form").find('.uwp-field-error').remove(); + } + jQuery.ajax({ url: uwp_localize_data.ajaxurl, type: 'POST', data: data, dataType: 'json' }).done(function(res, textStatus, jqXHR) { - if (typeof res == 'object' && res.success) { - $("#"+htmlvar+"_row").find(".uwp_file_preview_wrap").remove(); - $("#"+htmlvar).closest("td").find(".uwp_file_preview_wrap").remove(); - if($('input[name='+htmlvar+']').data( 'is-required' )){ - $('input[name='+htmlvar+']').prop('required',true); + if (res && typeof res == 'object') { + if (res.success) { + $("#"+htmlvar+"_row").find(".uwp_file_preview_wrap").remove(); + $("#"+htmlvar).closest("td").find(".uwp_file_preview_wrap").remove(); + if($('input[name='+htmlvar+']').data( 'is-required' )){ + $('input[name='+htmlvar+']').prop('required',true); + } + } else if (res.data && typeof res.data == 'object' && res.data.message) { + $this.parent(".uwp_file_preview_wrap").append('<div class="uwp-field-error">' + res.data.message + '</div>'); } } }); ... (truncated)
Exploit Outline
The exploit targets the 'uwp_upload_file_remove' AJAX action, which is intended to allow users to remove uploaded files by clearing a specific usermeta key. 1. Authentication: The attacker logs into the WordPress site with a Subscriber account. 2. Nonce Acquisition: The attacker navigates to their own profile or account page to retrieve the required AJAX nonce stored in 'uwp_localize_data.basicNonce'. 3. Payload Construction: The attacker crafts a POST request to '/wp-admin/admin-ajax.php' with the following parameters: - 'action': 'uwp_upload_file_remove' - 'htmlvar': The target usermeta key (e.g., 'wp_capabilities' or any 'for_admin_use' field). - 'uid': The attacker's own user ID. - 'security': The captured 'basicNonce'. 4. Execution: Because the server-side handler fails to validate that the provided 'htmlvar' corresponds to an actual file field or an authorized metadata key, the plugin executes 'delete_user_meta' or 'update_user_meta' on the sensitive key, effectively clearing it for the attacker's account.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.