Custom Admin Interface <= 7.41 - Missing Authorization
Description
The WP Custom Admin Interface plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 7.41. This makes it possible for authenticated attackers, with Subscriber-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=7.41What Changed in the Fix
Changes introduced in v7.42
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-25011 ## 1. Vulnerability Summary The **WP Custom Admin Interface** plugin (versions <= 7.41) contains a missing authorization vulnerability. Specifically, several AJAX actions and/or initialization hooks lack a `current_user_can('manage_options')` check. Thi…
Show full research plan
Exploitation Research Plan - CVE-2026-25011
1. Vulnerability Summary
The WP Custom Admin Interface plugin (versions <= 7.41) contains a missing authorization vulnerability. Specifically, several AJAX actions and/or initialization hooks lack a current_user_can('manage_options') check. This allows authenticated users with Subscriber-level permissions to perform administrative actions such as modifying plugin settings, resetting admin menus, or injecting custom content into the admin interface.
2. Attack Vector Analysis
- Vulnerable Endpoints:
/wp-admin/admin-ajax.php(Primary)/index.php(via query parameters, per the plugin's "delete-menu" feature)
- Vulnerable Actions:
wp_ajax_wp_custom_admin_interface_save_settingswp_ajax_wp_custom_admin_interface_reset_settingswp_custom_admin_interface_delete_menu(viainithook)
- Required Capability: Subscriber level access (
PR:L). - Payload Parameters:
action:wp_custom_admin_interface_save_settingssecurity: The nonce value.data: A serialized string or object containing the settings to be updated.
3. Code Flow
- Registration: The plugin registers AJAX handlers in
wp-custom-admin-interface.php(or an included settings file) usingadd_action( 'wp_ajax_wp_custom_admin_interface_save_settings', ... ). - Missing Check: The handler function (e.g.,
wp_custom_admin_interface_save_settings()) usescheck_ajax_referer( 'wp_custom_admin_interface_nonce', 'security' )to verify the nonce but fails to callcurrent_user_can( 'manage_options' ). - Execution: Since
wp_ajax_hooks are available to any logged-in user, and Subscribers can access the dashboard to receive the enqueued nonce, they can trigger the function. - Sink: The function calls
update_option(), allowing the Subscriber to overwrite the plugin's configuration.
4. Nonce Acquisition Strategy
The plugin enqueues its settings script and localizes a nonce for AJAX operations. Although the settings page is restricted, the script is often enqueued globally in the admin area.
- Navigate to Dashboard: Log in as a Subscriber and go to
/wp-admin/index.php. - Extract Nonce: Use
browser_evalto extract the nonce from the localized JavaScript object.- JS Object:
window.wp_custom_admin_interface_settings(inferred from plugin slug) - Key:
nonce - Command:
browser_eval("window.wp_custom_admin_interface_settings?.nonce")
- JS Object:
- Alternative: If not localized there, search the page source for any string containing
wp_custom_admin_interface_nonce.
5. Exploitation Strategy
We will attempt to modify the Admin Footer Text setting to demonstrate unauthorized integrity modification.
Step-by-Step Plan:
- Pre-exploitation: As Admin, set the footer text to "Original Admin Footer".
- Authentication: Authenticate as a Subscriber.
- Nonce Capture: Use the browser to navigate to
/wp-admin/index.phpand extract thesecuritynonce fromwindow.wp_custom_admin_interface_settings.nonce. - Execution: Send a POST request to
admin-ajax.phpto overwrite settings.- URL:
http://vulnerable-test.local/wp-admin/admin-ajax.php - Method:
POST - Content-Type:
application/x-www-form-urlencoded - Body:
action=wp_custom_admin_interface_save_settings&security=[NONCE]&data=wp_custom_admin_interface_general_settings%5Bfooter_text%5D=Exploited+by+Subscriber - Note: If
datarequires a JSON string instead of form-encoded, adjust the payload accordingly.
- URL:
6. Test Data Setup
- Users:
- Admin:
admin/password - Subscriber:
attacker/password
- Admin:
- Plugin Configuration:
- Ensure the plugin is active.
- As Admin, go to Custom Admin Interface > General Settings and set "Custom Footer Text" to "Standard Footer".
- Save changes.
7. Expected Results
- The AJAX request should return a
200 OKor a JSON success response (e.g.,{"success":true}). - The WordPress database option
wp_custom_admin_interface_general_settingsshould now contain "Exploited by Subscriber" in thefooter_textfield.
8. Verification Steps
- Check via WP-CLI:
Verify that thewp option get wp_custom_admin_interface_general_settings --format=jsonfooter_textvalue has changed. - Check Admin UI: Log in as Admin and navigate to any admin page. Scroll to the bottom and verify the footer text has been modified to "Exploited by Subscriber".
9. Alternative Approaches
The "Delete Menu" Bypass
The readme.txt mentions a feature to delete menus via a GET parameter. If the AJAX path fails, try this:
- URL:
http://vulnerable-test.local/index.php?wp-custom-admin-interface=delete-menu - Method:
GET(while logged in as Subscriber) - Verification: Check if the option
wp_custom_admin_interface_admin_menu_settingsis deleted:
(Expected: "Error: Could not find 'wp_custom_admin_interface_admin_menu_settings' option.")wp option get wp_custom_admin_interface_admin_menu_settings
Summary
The WP Custom Admin Interface plugin for WordPress is vulnerable to unauthorized access because it fails to perform capability checks on administrative functions registered via AJAX. This allows authenticated users with Subscriber-level access to perform unauthorized actions such as clearing transients or potentially modifying plugin settings.
Vulnerable Code
// wp-custom-admin-interface.php line 2476 function wp_custom_admin_interface_delete_dismiss_transients() { global $wpdb; $sql = "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_an_dismiss_%'"; $wpdb->query($sql); echo "success"; die(); } add_action( 'wp_ajax_delete_dismiss_transients', 'wp_custom_admin_interface_delete_dismiss_transients');
Security Fix
@@ -2474,11 +2474,16 @@ * Function to clear transients related to the admin notice */ function wp_custom_admin_interface_delete_dismiss_transients() { - global $wpdb; - $sql = "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_an_dismiss_%'"; - $wpdb->query($sql); - echo "success"; + + if ( current_user_can( 'administrator' ) ) { + + global $wpdb; + $sql = "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_an_dismiss_%'"; + $wpdb->query($sql); + echo "success"; + } die(); + } add_action( 'wp_ajax_delete_dismiss_transients', 'wp_custom_admin_interface_delete_dismiss_transients');
Exploit Outline
The exploit targets missing authorization checks in the plugin's AJAX handlers. 1. Authentication: The attacker authenticates as a Subscriber-level user. 2. Nonce Retrieval: The attacker navigates to the WordPress dashboard (/wp-admin/) and extracts the 'wp_custom_admin_interface_nonce' or the 'security' parameter from localized scripts (like window.wp_custom_admin_interface_settings). 3. Unauthorized Action: The attacker sends a POST request to /wp-admin/admin-ajax.php with the 'action' parameter set to 'delete_dismiss_transients' or 'wp_custom_admin_interface_save_settings', including the captured nonce. 4. Impact: Because the backend function only checks the nonce and not the user's capabilities, the administrative action (such as deleting transients or updating plugin options) is executed on behalf of the Subscriber.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.