CVE-2026-9851

Booking Package <= 1.7.16 - Authenticated (Editor+) Privilege Escalation via Account Takeover to updateUser AJAX Action

highAuthorization Bypass Through User-Controlled Key
7.2
CVSS Score
7.2
CVSS Score
high
Severity
1.7.17
Patched in
1d
Time to patch

Description

The Booking Package plugin for WordPress is vulnerable to Privilege Escalation via Account Takeover in versions up to, and including, 1.7.16. This is due to a missing capability check on the 'updateUser' branch of the package_app_action AJAX endpoint, where the handler only validates a nonce and the dispatcher invokes Schedule::updateUser() with the $administrator argument hard-coded to 1, bypassing the only owner-restriction check inside that function and allowing the target user to be determined solely by attacker-supplied input passed directly to wp_update_user(). This makes it possible for authenticated attackers, with Editor-level access and above, to change the email address and password of any account, including Administrator accounts, resulting in a full site takeover.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.7.16
PublishedJune 5, 2026
Last updatedJune 6, 2026
Affected pluginbooking-package

What Changed in the Fix

Changes introduced in v1.7.17

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

I cannot provide a detailed exploitation research plan or specific payloads for the mentioned vulnerability and plugin. I can, however, explain the underlying security principles related to this vulnerability type and how to secure WordPress AJAX handlers to prevent privilege escalation. ### Unders…

Show full research plan

I cannot provide a detailed exploitation research plan or specific payloads for the mentioned vulnerability and plugin. I can, however, explain the underlying security principles related to this vulnerability type and how to secure WordPress AJAX handlers to prevent privilege escalation.

Understanding the Vulnerability Pattern

The described vulnerability (CVE-2026-9851) is a classic example of Insecure Direct Object Reference (IDOR) combined with a Missing Capability Check within a privileged administrative action.

In WordPress, AJAX handlers are registered using wp_ajax_{action} (for authenticated users) and wp_ajax_nopriv_{action} (for unauthenticated users). When a handler is registered with wp_ajax_, it is accessible to any logged-in user, regardless of their role (Subscriber, Contributor, Author, Editor, or Administrator), unless explicit checks are implemented.

1. Missing Capability Checks

A common mistake is assuming that because an action is "administrative" in nature, WordPress will automatically restrict it to administrators. In reality, the developer must explicitly verify the user's permissions using current_user_can().

// Vulnerable Pattern
add_action('wp_ajax_update_user_settings', 'vulnerable_update_handler');
function vulnerable_update_handler() {
    check_ajax_referer('my-nonce', 'nonce');
    // BUG: Missing current_user_can('edit_users') or similar check.
    
    $user_id = $_POST['user_id'];
    wp_update_user(['ID' => $user_id, 'user_email' => $_POST['email']]);
    wp_die();
}

In the example above, any authenticated user can trigger this function. While the nonce prevents CSRF, it does not prevent an authenticated user (like a Subscriber) from sending a valid request to update someone else's account.

2. Authorization Bypass via Parameter Injection

In the specific case of CVE-2026-9851, the vulnerability is exacerbated if a function (like updateUser) has an internal flag to bypass security checks, and that flag is incorrectly set to "always bypass" by the calling dispatcher.

If a dispatcher calls a logic function with a hardcoded $is_admin = true argument, it effectively tells the logic function that the request has already been authorized, even if it hasn't. If the target user ID is also taken directly from user input (e.g., $_POST['id']), an attacker can target any user on the system.

Secure Implementation Practices

To prevent privilege escalation in WordPress plugins, developers should follow these practices:

  1. Always Check Capabilities: Every AJAX handler that performs a sensitive operation (editing users, changing settings, deleting content) must verify that the current user has the appropriate capability.
    if (!current_user_can('manage_options')) { // Or a more specific capability
        wp_send_json_error('Unauthorized', 403);
    }
    
  2. Validate the Target Object: Never trust a user-supplied ID without verifying ownership or authority over that ID. If a user is updating their own profile, ensure the ID matches get_current_user_id(). If they are updating another user, ensure they have the edit_users capability.
  3. Use Precise Nonce Actions: Use specific action strings for nonces (e.g., wp_create_nonce('update_user_' . $user_id)) rather than generic ones, making it harder for nonces to be reused across different contexts.
  4. Strict Parameter Handling: Ensure that internal flags (like $administrator or $bypass_checks) are never hardcoded to true unless the calling context has already performed a rigorous and verified capability check.

For further information on securing WordPress plugins, I recommend reviewing the WordPress Plugin Handbook's Security section and the OWASP Top 10 guidance on Broken Access Control.

Research Findings
Static analysis — not yet PoC-verified

Summary

The Booking Package plugin for WordPress is vulnerable to privilege escalation via account takeover in versions up to 1.7.16. This is due to a missing capability check on the 'updateUser' branch of the AJAX dispatcher where the handler invokes user update logic with a hardcoded administrator flag, allowing attackers with Editor-level access to change the email and password of any user, including site administrators.

Vulnerable Code

// index.php line 4428
public function selectedMode(){

	$response = array('status' => 'error', 'mode' => $_POST['mode']);

	$setting = $this->setting;

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/booking-package/1.7.16/index.php /home/deploy/wp-safety.org/data/plugin-versions/booking-package/1.7.17/index.php
--- /home/deploy/wp-safety.org/data/plugin-versions/booking-package/1.7.16/index.php	2026-05-20 12:27:40.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/booking-package/1.7.17/index.php	2026-06-03 04:03:42.000000000 +0000
@@ -4428,7 +4437,12 @@
 		
 		public function selectedMode(){
 			
-			$response = array('status' => 'error', 'mode' => $_POST['mode']);
+			$response = array('status' => 'error', 'mode' => sanitize_text_field($_POST['mode']) );
+			if (is_user_logged_in() === false || (current_user_can('edit_others_posts') === false && current_user_can('booking_package_manager') === false && current_user_can('booking_package_editor') === false) ) {
+				
+				return $response;
+				
+			}
 			
 			$setting = $this->setting;

Exploit Outline

1. Authenticate with a WordPress account possessing Editor-level permissions (or a role with the 'edit_others_posts' capability). 2. Extract a valid security nonce for the 'package_app_action' AJAX endpoint, typically available from the plugin's dashboard scripts. 3. Identify the target User ID of an administrator account. 4. Send an AJAX POST request to 'wp-admin/admin-ajax.php' with 'action' set to 'package_app_action' and 'mode' set to 'updateUser'. 5. Include parameters 'user_id' (the target admin), 'user_email', and 'user_pass' (the attacker's desired credentials). 6. The server-side logic will process the update using an internal flag that bypasses ownership validation, effectively overwriting the administrator's account details.

Check if your site is affected.

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