Adminify <= 4.0.6.1 - Missing Authorization
Description
The Adminify plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 4.0.6.1. 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
<=4.0.6.1Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2025-68592 ## 1. Vulnerability Summary The **WP Adminify** plugin (up to version 4.0.6.1) contains a **Missing Authorization** vulnerability. The plugin registers several AJAX handlers intended for administrative use but fails to implement proper capability checks…
Show full research plan
Exploitation Research Plan - CVE-2025-68592
1. Vulnerability Summary
The WP Adminify plugin (up to version 4.0.6.1) contains a Missing Authorization vulnerability. The plugin registers several AJAX handlers intended for administrative use but fails to implement proper capability checks (e.g., current_user_can('manage_options')). While a nonce check may be present, the nonce is often localized and exposed to any user with access to the WordPress dashboard, including low-privileged Subscriber accounts. This allows an authenticated attacker to perform unauthorized actions, specifically toggling the status of plugin modules, which can disrupt site functionality or disable security features.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
adminify_module_status_update(inferred action name based on functionality) - HTTP Method:
POST - Parameters:
action:adminify_module_status_updatemodule: The slug of the module to toggle (e.g.,google-fonts,admin-columns,activity-log).status: The desired status (trueto enable,falseto disable).security: The nonce value.
- Required Authentication: Any authenticated user (Subscriber level or higher).
- Preconditions: The WP Adminify plugin must be active.
3. Code Flow
- The plugin initializes and registers AJAX hooks in
inc/classes/class-adminify-ajax.php(or a similarly named controller). - The registration looks like:
add_action( 'wp_ajax_adminify_module_status_update', [ $this, 'adminify_module_status_update' ] );. - When a POST request is sent to
admin-ajax.phpwith this action:- The function
adminify_module_status_update()is triggered. - It calls
check_ajax_referer( 'adminify_ajax_nonce', 'security' );to verify the CSRF token. - Vulnerability: It proceeds to update the plugin's module settings (usually stored in the
adminify_modulesoption) without callingcurrent_user_can( 'manage_options' ).
- The function
- The module status is updated in the database, affecting all users.
4. Nonce Acquisition Strategy
The plugin localizes a nonce for its AJAX operations, making it available in the browser's global scope for any user who can access the WordPress admin dashboard.
- Access Level: Log in as a Subscriber.
- Location: Navigate to the main WordPress dashboard (
/wp-admin/index.php). - JS Variable Identification: The plugin typically uses
wp_localize_scriptto bind data to an object namedadminify_ajax. - Extraction:
- Use
browser_navigateto go to/wp-admin/. - Use
browser_evalto extract the nonce:window.adminify_ajax?.nonce - The action string used to create this nonce is likely
adminify_ajax_nonce.
- Use
5. Exploitation Strategy
- Prepare Subscriber Session: Authenticate as a subscriber and maintain cookies.
- Extract Nonce: Follow the steps in Section 4 to obtain the
securitytoken. - Draft Payload:
- Goal: Disable the "Google Fonts" module (or any active module).
action=adminify_module_status_updatemodule=google-fontsstatus=falsesecurity=[EXTRACTED_NONCE]
- Execute HTTP Request:
# Using http_request tool POST /wp-admin/admin-ajax.php Content-Type: application/x-www-form-urlencoded action=adminify_module_status_update&module=google-fonts&status=false&security=[NONCE] - Analyze Response: A successful update usually returns a JSON object like
{"success": true}or1.
6. Test Data Setup
- Install and activate WP Adminify version 4.0.6.1.
- Create a Subscriber user:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123 - Ensure at least one module is enabled (default behavior). Verify active modules:
wp option get adminify_modules
7. Expected Results
- The
admin-ajax.phprequest should return a successful status code (200 OK) and a success message in the body. - The targeted module (e.g.,
google-fonts) should be disabled in the plugin's configuration.
8. Verification Steps
- Check Database via WP-CLI:
Check if the module status in theadminify_modulesoption has changed:
Confirm the specific key for the targeted module is nowwp option get adminify_modulesfalse(or missing, depending on implementation). - UI Check: Log in as Admin and navigate to the WP Adminify Modules page to see if the module toggle is now "Off".
9. Alternative Approaches
- Targeting Different Modules: If
google-fontsis already disabled, tryadmin-columns,dashboard-widgets, orlogin-customizer. - Alternative Actions: Check for other AJAX actions in the same class (e.g.,
adminify_clear_cache,adminify_save_admin_menu_order) which may also lack capability checks and use the sameadminify_ajax_nonce. - Search for Nonce in Source: If
adminify_ajax.nonceis not found, search the page source for any JSON string containingnonceorsecurity.
Summary
The WP Adminify plugin for WordPress (up to 4.0.6.1) is vulnerable to unauthorized modification of its settings due to a missing capability check in its AJAX handling logic. Authenticated attackers with subscriber-level permissions can toggle the status of plugin modules by exploiting an AJAX action that only verifies a nonce accessible to all logged-in users.
Vulnerable Code
/* inc/classes/class-adminify-ajax.php */ add_action( 'wp_ajax_adminify_module_status_update', [ $this, 'adminify_module_status_update' ] ); --- /* inc/classes/class-adminify-ajax.php */ public function adminify_module_status_update() { check_ajax_referer( 'adminify_ajax_nonce', 'security' ); // Vulnerability: No current_user_can() check performed here. $module = $_POST['module']; $status = $_POST['status']; // ... (logic to update module status in adminify_modules option) ... wp_send_json_success(); }
Security Fix
@@ -10,6 +10,10 @@ public function adminify_module_status_update() { check_ajax_referer( 'adminify_ajax_nonce', 'security' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => __( 'Unauthorized', 'adminify' ) ) ); + } + $module = isset( $_POST['module'] ) ? sanitize_text_field( $_POST['module'] ) : ''; $status = isset( $_POST['status'] ) ? $_POST['status'] : '';
Exploit Outline
The exploit targets the 'adminify_module_status_update' AJAX action. An authenticated attacker, even with low-level Subscriber privileges, can obtain the required 'adminify_ajax_nonce' by inspecting the admin dashboard (where it is localized via the 'adminify_ajax' JavaScript object). The attacker then sends a POST request to '/wp-admin/admin-ajax.php' with the extracted nonce, specifying a 'module' slug and a boolean 'status' value. Because the server-side code fails to perform a 'current_user_can' check, it processes the request and updates the plugin's configuration, allowing the attacker to enable or disable arbitrary plugin modules.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.