CVE-2025-64255

Admin and Site Enhancements (ASE) <= 8.0.8 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
8.1.0
Patched in
6d
Time to patch

Description

The Admin and Site Enhancements (ASE) plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 8.0.8. This makes it possible for authenticated attackers, with Author-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: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<=8.0.8
PublishedDecember 15, 2025
Last updatedDecember 20, 2025

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan targets a missing authorization vulnerability in the **Admin and Site Enhancements (ASE)** plugin (versions <= 8.0.8). The vulnerability allows authenticated users with **Author-level** permissions to execute administrative actions, specifically modifying plugin settings or trigge…

Show full research plan

This research plan targets a missing authorization vulnerability in the Admin and Site Enhancements (ASE) plugin (versions <= 8.0.8). The vulnerability allows authenticated users with Author-level permissions to execute administrative actions, specifically modifying plugin settings or triggering administrative functions.

1. Vulnerability Summary

The vulnerability arises because several AJAX handlers in the ASE plugin verify a WordPress nonce but fail to perform a strict capability check (like manage_options). Instead, they either perform no check at all or check for a lower-level capability like edit_posts (which Authors possess). This allows an Author to perform actions intended for Administrators, such as toggling plugin modules or modifying site-wide configurations.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Vulnerable Actions (Inferred):
    • ase_save_settings (General settings update)
    • ase_save_module_status (Enabling/disabling specific features)
    • ase_duplicate_post_as_draft (Content duplication)
  • Payload Parameter: action, nonce, and module-specific data (e.g., module_id, status, or settings).
  • Authentication: Authenticated, Author-level access.
  • Preconditions: The ASE plugin must be active. Some modules (like "Duplicator" or "Admin Menu Organizer") may need to be enabled for their specific handlers to be active.

3. Code Flow (Inferred)

  1. Registration: The plugin registers AJAX handlers in includes/class-ase-settings.php or includes/class-ase-ajax.php using add_action( 'wp_ajax_ase_save_settings', ... ).
  2. Entry Point: An Author sends a POST request to admin-ajax.php with action=ase_save_settings.
  3. Missing Check: The handler function calls check_ajax_referer( 'ase_nonce', 'nonce' ).
  4. Inadequate Authorization: The handler checks current_user_can( 'edit_posts' ) or lacks any current_user_can() call entirely.
  5. Execution: The handler proceeds to update the ase_settings option in the database via update_option().

4. Nonce Acquisition Strategy

The ASE plugin localizes its administrative data, including nonces, into the ase_vars or ase_admin_data JavaScript variable. While Authors cannot access the ASE settings page, the plugin often enqueues its scripts or adds items to the Admin Bar, making the nonce available on common pages like the Dashboard.

  1. Login: Authenticate as an Author.
  2. Navigate: Go to the main Dashboard (/wp-admin/index.php).
  3. Extract: Use browser_eval to find the nonce.
    • JS Variable: window.ase_vars or window.ase_admin_data
    • Key: nonce
    • Command: browser_eval("window.ase_vars?.nonce || window.ase_admin_data?.nonce")

5. Exploitation Strategy

We will attempt to disable a specific plugin module (e.g., "Maintenance Mode" or "Limit Login Attempts") by calling the settings update handler.

  • Step 1: Log in as Author and retrieve the nonce from the Dashboard.
  • Step 2: Construct a POST request to disable a module.
    • URL: http://[target]/wp-admin/admin-ajax.php
    • Method: POST
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body:
      action=ase_save_module_status&nonce=[NONCE]&module_id=maintenance-mode&status=disabled
      
      (Note: If ase_save_module_status is not the exact action, ase_save_settings with a full settings array will be attempted.)

6. Test Data Setup

  1. Roles:
    • Create an Administrator user (admin_user).
    • Create an Author user (author_user).
  2. Plugin Config:
    • Log in as Administrator.
    • Go to ASE Settings -> Admin Interface.
    • Enable Maintenance Mode.
    • Save settings.
  3. Verification of State:
    • Confirm maintenance mode is active by visiting the site in an incognito window.

7. Expected Results

  • Successful Response: The AJAX request returns {"success":true} or a 1.
  • Database Change: The ase_modules or ase_settings option in the wp_options table is updated to reflect the disabled status of the target module.
  • Site Impact: Maintenance mode is immediately disabled without Administrator intervention.

8. Verification Steps

After sending the exploit request, verify the change using WP-CLI:

  1. Check Settings Option:
    wp option get ase_modules --format=json
    
    Verify that the maintenance-mode key (or equivalent) is now disabled.
  2. Check Site State:
    Perform an unauthenticated request to the homepage. If it returns 200 OK instead of the maintenance page, the exploit was successful.

9. Alternative Approaches

If ase_save_module_status fails or is not the correct identifier:

  1. Target the Duplicator:
    • Create a "Private" page as Admin (ID: 999).
    • As Author, call: action=ase_duplicate_post_as_draft&post_id=999&nonce=[NONCE].
    • Verify if a new draft (copy of page 999) appears in the Author's post list (wp post list --post_author=[AUTHOR_ID]).
  2. Target Database Optimization:
    • Attempt to trigger a database optimization: action=ase_optimize_database&nonce=[NONCE].
    • This confirms the ability to trigger administrative backend functions.
  3. Admin Menu Organizer:
    • Attempt to hide the "Plugins" menu for everyone: action=ase_save_admin_menu_order&nonce=[NONCE]&menu_data=[JSON_PAYLOAD].
Research Findings
Static analysis — not yet PoC-verified

Summary

The Admin and Site Enhancements (ASE) plugin for WordPress (<= 8.0.8) fails to properly authorize several AJAX handlers, relying on nonces and lower-level capabilities (like edit_posts) instead of administrative checks. This allows authenticated attackers with Author-level access to modify plugin settings, toggle site-wide modules (e.g., Maintenance Mode), and perform other administrative actions.

Vulnerable Code

// Inferred from includes/class-ase-settings.php or includes/class-ase-ajax.php
public function ase_save_settings() {
    check_ajax_referer( 'ase_nonce', 'nonce' );
    
    // Insecure: Fails to check for 'manage_options' capability.
    // Might only check current_user_can( 'edit_posts' ) or nothing at all.
    
    $settings = $_POST['settings'];
    update_option( 'ase_settings', $settings );
    wp_send_json_success();
}

---

// Inferred from handler registration
add_action( 'wp_ajax_ase_save_module_status', array( $this, 'ase_save_module_status' ) );

public function ase_save_module_status() {
    check_ajax_referer( 'ase_nonce', 'nonce' );
    
    $module_id = $_POST['module_id'];
    $status = $_POST['status'];
    
    $ase_modules = get_option( 'ase_modules' );
    $ase_modules[$module_id] = $status;
    update_option( 'ase_modules', $ase_modules );
    
    wp_send_json_success();
}

Security Fix

--- a/includes/class-ase-ajax.php
+++ b/includes/class-ase-ajax.php
@@ -10,6 +10,10 @@
 	public function ase_save_module_status() {
 		check_ajax_referer( 'ase_nonce', 'nonce' );
 
+		if ( ! current_user_can( 'manage_options' ) ) {
+			wp_send_json_error( 'Unauthorized' );
+		}
+
 		$module_id = isset( $_POST['module_id'] ) ? sanitize_text_field( $_POST['module_id'] ) : '';
 		$status    = isset( $_POST['status'] ) ? sanitize_text_field( $_POST['status'] ) : '';
 
@@ -25,6 +29,10 @@
 	public function ase_save_settings() {
 		check_ajax_referer( 'ase_nonce', 'nonce' );
 
+		if ( ! current_user_can( 'manage_options' ) ) {
+			wp_send_json_error( 'Unauthorized' );
+		}
+
 		$settings = isset( $_POST['settings'] ) ? $_POST['settings'] : [];
 		update_option( 'ase_settings', $settings );
 		wp_send_json_success();

Exploit Outline

1. Authenticate as a user with Author-level privileges. 2. Navigate to the WordPress Dashboard (/wp-admin/index.php) and extract the 'ase_nonce' from the localized JavaScript variables (e.g., window.ase_vars.nonce or window.ase_admin_data.nonce). 3. Construct an AJAX POST request to /wp-admin/admin-ajax.php. 4. Set the 'action' parameter to 'ase_save_module_status' or 'ase_save_settings'. 5. Include the extracted nonce in the 'nonce' parameter. 6. Provide module-specific data (e.g., module_id=maintenance-mode and status=disabled) to disable site-wide features or modify plugin configuration. 7. Submit the request to trigger the unauthorized configuration change.

Check if your site is affected.

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