CVE-2025-14081

Ultimate Member <= 2.11.0 - Authenticated (Subscriber+) Profile Privacy Setting Bypass

mediumIncorrect Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
2.11.1
Patched in
2d
Time to patch

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: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<=2.11.0
PublishedDecember 16, 2025
Last updatedDecember 17, 2025
Affected pluginultimate-member

Source Code

WordPress.org SVN
Research Plan
Unverified

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 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)

  1. Entry Point: User submits the Account update form via POST to the account page.
  2. Handler: The UM()->account()->process_update() function (or similar in includes/core/class-account.php) is triggered.
  3. Field Discovery: The plugin iterates through the fields defined for the "privacy" tab.
  4. Vulnerable Logic:
    • The code iterates through the fields and adds their keys to an internal $allowed_fields array.
    • The Bug: It adds the key to $allowed_fields before checking if the current user meets the required_perm criteria.
  5. Validation & Save: The plugin checks if $_POST['profile_privacy'] exists and if the key profile_privacy is in the $allowed_fields array. Since it is present, the validation passes, and update_user_meta is 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.

  1. Login: Log in as a Subscriber.
  2. Navigate: Navigate to the /account/ page (or the page where the UM Account shortcode [ultimatemember_account] is placed).
  3. Extraction:
    • Use browser_eval to extract the nonce from the form or the um_scripts localized object.
    • The account form typically contains a hidden field named _wpnonce or um_account_nonce.
    • JS Command: browser_eval("document.querySelector('input[name=\"_wpnonce\"]')?.value") or check the um_account_params global.

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.

  1. Determine the Tab: Identify the tab slug for privacy, usually privacy.

  2. Construct Payload:

    • _um_account_tab: privacy
    • profile_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)
  3. 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

  1. Enable UM Account: Ensure a page with [ultimatemember_account] exists.
  2. Configure Privacy Tab: In WP Admin -> Ultimate Member -> Settings -> Appearance -> Account, ensure the "Privacy" tab is enabled.
  3. Restrict Access: Use a hook or the UM Form Builder to set a required_perm on the profile_privacy field that the Subscriber does NOT have (e.g., manage_options).
    • Manual DB/Option setup: Alternatively, manipulate the um_options or form metadata to ensure the field is "hidden" but defined in the form structure.
  4. Create User: Create a Subscriber user.

7. Expected Results

  • Response: The server returns a 302 Redirect back to the account page with a success message or a 200 OK containing "Changes saved".
  • Logic: Even though the Subscriber could not see the "Profile Privacy" dropdown in their browser, the backend accepted the profile_privacy parameter and updated the user's meta.

8. Verification Steps

  1. WP-CLI Check: Verify the user meta directly.
    wp user meta get <subscriber_id> profile_privacy
    
    Success: The value should be only_me.
  2. 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_update action.
    • Action: wp_ajax_um_account_update
    • Data: action=um_account_update&nonce=...&profile_privacy=only_me&tab=privacy
  • Different Privacy Keys: If profile_privacy isn't the key, check for account_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.