Ultimate Member <= 2.11.0 - Authenticated (Subscriber+) Profile Privacy Setting Bypass
Description
The Ultimate Member plugin for WordPress is vulnerable to Profile Privacy Setting Bypass in all versions up to, and including, 2.11.0. This is due to a flaw in the secure fields mechanism where field keys are stored in the allowed fields list before the `required_perm` check is applied during rendering. This makes it possible for authenticated attackers with Subscriber-level access to modify their profile privacy settings (e.g., setting profile to "Only me") via direct parameter manipulation, even when the administrator has explicitly disabled the option for their role.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=2.11.0Source Code
WordPress.org SVNThis research plan focuses on exploiting **CVE-2025-14081**, an authenticated profile privacy bypass in the Ultimate Member plugin. ### 1. Vulnerability Summary The Ultimate Member plugin (<= 2.11.0) contains an authorization bypass in its "secure fields" mechanism. When a user updates their accoun…
Show full research plan
This research plan focuses on exploiting CVE-2025-14081, an authenticated profile privacy bypass in the Ultimate Member plugin.
1. Vulnerability Summary
The Ultimate Member plugin (<= 2.11.0) contains an authorization bypass in its "secure fields" mechanism. When a user updates their account or profile, the plugin generates a list of "allowed fields" based on the form configuration. The vulnerability exists because the plugin populates this allowed list with field keys before verifying the required_perm (required permission) attribute of those fields. Consequently, if a field (like profile_privacy) is configured in the form but restricted from a specific role (e.g., Subscriber) via permissions, the plugin still includes the key in the allowed list, permitting the user to modify it via direct parameter manipulation during a POST request.
2. Attack Vector Analysis
- Endpoint: The standard Ultimate Member Account page (typically at
/account/) or the AJAX handler for profile updates. - Authentication: Authenticated, Subscriber-level access is required.
- Vulnerable Parameter:
profile_privacy(or the specific key used for privacy settings, often prefixed depending on the form context). - Precondition: The administrator must have configured the "Privacy" tab/fields in the Account settings but restricted visibility or editability for the Subscriber role (e.g., by setting a "Required Permission" that the Subscriber lacks).
3. Code Flow (Inferred from Patch/Description)
- Entry Point: User submits the Account update form via
POSTto the account page. - Handler: The
UM()->account()->process_update()function (or similar inincludes/core/class-account.php) is triggered. - Field Discovery: The plugin iterates through the fields defined for the "privacy" tab.
- Vulnerable Logic:
- The code iterates through the fields and adds their keys to an internal
$allowed_fieldsarray. - The Bug: It adds the key to
$allowed_fieldsbefore checking if the current user meets therequired_permcriteria.
- The code iterates through the fields and adds their keys to an internal
- Validation & Save: The plugin checks if
$_POST['profile_privacy']exists and if the keyprofile_privacyis in the$allowed_fieldsarray. Since it is present, the validation passes, andupdate_user_metais called with the attacker-supplied value.
4. Nonce Acquisition Strategy
Ultimate Member uses standard WordPress nonces and its own form nonces on the account page.
- Login: Log in as a Subscriber.
- Navigate: Navigate to the
/account/page (or the page where the UM Account shortcode[ultimatemember_account]is placed). - Extraction:
- Use
browser_evalto extract the nonce from the form or theum_scriptslocalized object. - The account form typically contains a hidden field named
_wpnonceorum_account_nonce. - JS Command:
browser_eval("document.querySelector('input[name=\"_wpnonce\"]')?.value")or check theum_account_paramsglobal.
- Use
5. Exploitation Strategy
The goal is to change the profile_privacy setting to only_me even when the UI for this setting is hidden/disabled for the user.
Determine the Tab: Identify the tab slug for privacy, usually
privacy.Construct Payload:
_um_account_tab:privacyprofile_privacy:only_me(The value we want to force)um_account_submit_privacy:1(To trigger the specific tab update logic)_wpnonce: (The extracted nonce)_um_account_id: (Current user ID)
HTTP Request (Playwright):
{ "method": "POST", "url": "http://localhost:8080/account/", "headers": { "Content-Type": "application/x-www-form-urlencoded" }, "params": { "profile_privacy": "only_me", "_um_account_tab": "privacy", "um_account_submit_privacy": "1", "_wpnonce": "NONCE_HERE", "user_id": "USER_ID_HERE" } }
6. Test Data Setup
- Enable UM Account: Ensure a page with
[ultimatemember_account]exists. - Configure Privacy Tab: In
WP Admin -> Ultimate Member -> Settings -> Appearance -> Account, ensure the "Privacy" tab is enabled. - Restrict Access: Use a hook or the UM Form Builder to set a
required_permon theprofile_privacyfield that the Subscriber does NOT have (e.g.,manage_options).- Manual DB/Option setup: Alternatively, manipulate the
um_optionsor form metadata to ensure the field is "hidden" but defined in the form structure.
- Manual DB/Option setup: Alternatively, manipulate the
- Create User: Create a Subscriber user.
7. Expected Results
- Response: The server returns a
302 Redirectback to the account page with a success message or a200 OKcontaining "Changes saved". - Logic: Even though the Subscriber could not see the "Profile Privacy" dropdown in their browser, the backend accepted the
profile_privacyparameter and updated the user's meta.
8. Verification Steps
- WP-CLI Check: Verify the user meta directly.
Success: The value should bewp user meta get <subscriber_id> profile_privacyonly_me. - Behavior Check: Try to view the Subscriber's profile as another user (or logged out).
- If it was public before and is now restricted, the bypass worked.
9. Alternative Approaches
- AJAX Endpoint: If the account page uses AJAX, look for the
um_account_updateaction.- Action:
wp_ajax_um_account_update - Data:
action=um_account_update&nonce=...&profile_privacy=only_me&tab=privacy
- Action:
- Different Privacy Keys: If
profile_privacyisn't the key, check foraccount_privacy_profile_view. (Inferred from UM version 2.x naming conventions). Verify the key by looking at the HTML source of the Account page as an Admin.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.