WP Docs <= 2.2.8 - Missing Authorization
Description
The WP Docs plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 2.2.8. 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
<=2.2.8What Changed in the Fix
Changes introduced in v2.2.9
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-24990 ## 1. Vulnerability Summary The **WP Docs** plugin for WordPress (versions <= 2.2.8) contains a **Missing Authorization** vulnerability in its AJAX handlers. Specifically, the function responsible for updating plugin settings (likely `wp_ajax_wpdocs_sav…
Show full research plan
Exploitation Research Plan - CVE-2026-24990
1. Vulnerability Summary
The WP Docs plugin for WordPress (versions <= 2.2.8) contains a Missing Authorization vulnerability in its AJAX handlers. Specifically, the function responsible for updating plugin settings (likely wp_ajax_wpdocs_save_settings) performs a nonce check but fails to verify if the requesting user has the necessary administrative capabilities (e.g., manage_options). This allows an authenticated attacker with Subscriber-level permissions to modify plugin configurations, such as allowed file extensions or user roles permitted to upload documents.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Action:
wpdocs_save_settings(inferred from the nonce actionwpdocs_update_options_noncelocalized ininc/functions.php). - HTTP Method: POST
- Payload Parameter:
wpdocs_options(array) - Authentication: Required (Subscriber level or higher).
- Preconditions: The attacker must be logged in. To pass the nonce check, the attacker must either obtain the
wpdocs_update_options_nonceor exploit a failure in the nonce verification (e.g., missing check or default action-1).
3. Code Flow
- Entry Point: The AJAX action
wp_ajax_wpdocs_save_settingsis triggered by a POST request toadmin-ajax.php. - Nonce Verification: The handler calls
check_ajax_referer('wpdocs_update_options_nonce', 'nonce'). - Missing Check: The handler omits a call to
current_user_can('manage_options'). - Data Processing: User input from
$_POST['wpdocs_options']is passed tosanitize_wpdocs_data()(defined ininc/functions.php). - Sink: The sanitized data is saved to the database using
update_option('wpdocs_options', ... ).
4. Nonce Acquisition Strategy
The nonce is generated in inc/functions.php within the wpdocs_admin_enqueue_script() function and localized to wpdocs_ajax_object.nonce.
// From inc/functions.php
wp_localize_script(
'wpdocs_admin_scripts',
'wpdocs_ajax_object',
array(
...
'nonce' => wp_create_nonce('wpdocs_update_options_nonce'),
...
)
);
Strategy:
- Accessing the Script: The script is enqueued if
$_GET['page'] == 'wpdocs'. While this page is typically restricted to admins, the vulnerability may stem from the fact that the plugin registers this page with a low capability requirement (e.g.,read) or that the nonce is leaked on other accessible admin pages. - Extraction:
- Log in as a Subscriber.
- Navigate to
wp-admin/admin.php?page=wpdocs. - Use
browser_evalto extract the nonce:window.wpdocs_ajax_object?.nonce. - If the page is inaccessible, try the exploit with a blank or invalid nonce to confirm if
check_ajax_refereris strictly enforced.
5. Exploitation Strategy
We will attempt to modify the plugin settings to allow Subscribers to upload files by adding the subscriber role to the upload_roles (or similar) setting.
Step-by-Step:
- Login: Authenticate as a Subscriber user.
- Nonce Retrieval: Navigate to the dashboard and check if
wpdocs_ajax_objectis available in the global JS scope. - Formulate Payload:
- Action:
wpdocs_save_settings - Nonce:
[extracted_nonce] - Data:
wpdocs_options[allowed_roles][]=subscriber&wpdocs_options[allowed_roles][]=administrator
- Action:
- Execute Request:
- Send a POST request using the
http_requesttool. - URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=wpdocs_save_settings&nonce=[NONCE]&wpdocs_options[allowed_roles][]=subscriber&wpdocs_options[allowed_roles][]=administrator
- Send a POST request using the
6. Test Data Setup
- Plugin: Install and activate WP Docs version 2.2.8.
- User: Create a user with the
subscriberrole (e.g.,attacker/attacker). - Initial State: Ensure the
wpdocs_optionsdoes not currently include the subscriber role in its allowed list.
7. Expected Results
- The server should return a
200 OKor a success JSON response (e.g.,{"success":true}). - The
wpdocs_optionsrecord in thewp_optionstable should be updated to include'subscriber'in the roles list.
8. Verification Steps
- WP-CLI Check: Verify the option change directly in the database.
wp option get wp
Summary
The WP Docs plugin for WordPress is vulnerable to unauthorized document management due to missing capability checks in the AJAX handlers for folder creation and deletion. Authenticated attackers with Subscriber-level access or higher can bypass intended administrative restrictions to create or delete document directories by providing a valid security nonce.
Vulnerable Code
// inc/functions.php line 627 (approx) function wpdocs_create_folder() { $nonce = sanitize_wpdocs_data(wp_unslash($_POST['nonce'])); if (!empty($_POST) && isset($_POST['nonce']) && ! wp_verify_nonce( $nonce, 'wpdocs_update_options_nonce' ) ) --- // inc/functions.php line 2020 (approx) function wpdocs_delete_folder() { $nonce = sanitize_wpdocs_data(wp_unslash($_POST['nonce'])); if (!empty($_POST) && isset($_POST['nonce']) && ! wp_verify_nonce( $nonce, 'wpdocs_update_options_nonce' ) )
Security Fix
@@ -626,6 +626,11 @@ function wpdocs_create_folder() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( __("Unauthorized user", 'wp-docs') ); + wp_die(); + } + $nonce = sanitize_wpdocs_data(wp_unslash($_POST['nonce'])); if (!empty($_POST) && isset($_POST['nonce']) && ! wp_verify_nonce( $nonce, 'wpdocs_update_options_nonce' ) ) @@ -2019,6 +2024,12 @@ function wpdocs_delete_folder() { + + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( __( 'Unauthorized user', 'wp-docs' ) ); + wp_die(); + } + $nonce = sanitize_wpdocs_data(wp_unslash($_POST['nonce'])); if (!empty($_POST) && isset($_POST['nonce']) && ! wp_verify_nonce( $nonce, 'wpdocs_update_options_nonce' ) )
Exploit Outline
To exploit this vulnerability, an attacker must first authenticate as a Subscriber. The attacker then retrieves the 'wpdocs_update_options_nonce' security token, which is localized in the JavaScript variable 'wpdocs_ajax_object.nonce' (often accessible via the admin dashboard or by navigating to plugin pages where scripts are enqueued). Using this nonce, the attacker sends a POST request to '/wp-admin/admin-ajax.php' with the 'action' parameter set to 'wpdocs_create_folder' (to create new directories) or 'wpdocs_delete_folder' (to delete existing ones). Because the server-side handlers only verify the nonce and not the user's capabilities, the requested operation is performed despite the attacker lacking administrative privileges.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.