Introduction
A missing capability check in the WordPress Booking Package plugin allows any Editor level user to hijack Administrator accounts with a single AJAX request, converting a common content management role into full site control. With over 10,000 active installations, this vulnerability affects a meaningful slice of small to medium business WordPress deployments that rely on the plugin for appointment booking, room rental, and event scheduling.
The Booking Package plugin, developed by SAASPROJECT (masaakitanaka on WordPress.org), provides online reservation and scheduling functionality directly within WordPress. It has been available since February 2018 and positions itself as a free solution with premium features, serving businesses that need booking capabilities without custom development.
Technical Information
CVE-2026-9851 is classified under CWE-639 (Authorization Bypass Through User-Controlled Key) and carries a CVSS v3.1 score of 7.2 with the vector CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H. The vulnerability affects versions up to and including 1.7.16 of the Booking Package plugin.
Root Cause: Three Layers of Missing Authorization
The vulnerability is the result of three interconnected failures in the plugin's authorization architecture. Each layer trusts the layer above it without performing independent validation, creating a complete defense in depth failure.
Layer 1: AJAX Entry Point (index.php, line 4416)
The package_app_action AJAX endpoint is registered for authenticated WordPress users. When a request arrives, the handler instantiates a booking_package_schedule object and reads the $_POST['action'] parameter to determine which method to invoke. At this stage, the handler validates only a WordPress nonce. It performs no capability check to verify whether the requesting user has the edit_users capability or any other privilege beyond basic authentication.
Layer 2: Unsafe Dynamic Dispatch (index.php, line 4477)
The dispatcher at line 4477 executes a dynamic method call using the client controlled $_POST['action'] value. When action=updateUser is supplied, the request routes directly to Schedule::updateUser(). There is no whitelist of permitted actions, no role verification, and no call to current_user_can() before this dispatch occurs. Any authenticated user who can reach the AJAX endpoint can invoke any method the dispatcher supports.
Layer 3: Hard Coded Authorization Bypass (Schedule.php, line 868)
The Schedule::updateUser() function accepts a $data array (containing the target user ID, email, password, and role) along with an $administrator boolean parameter. This $administrator parameter is the sole authorization gate inside the function: when it evaluates to true, the function bypasses its owner restriction check and passes all supplied fields, including role, directly to wp_update_user().
The critical flaw is that the dispatcher hard codes $administrator to 1 when calling this function. This means the authorization gate is always open, regardless of the actual privileges of the requesting user. The target user is determined entirely by attacker supplied input.
Attack Flow
An authenticated attacker with Editor level access exploits this vulnerability through the following sequence:
- The attacker authenticates to WordPress with an Editor account and obtains a valid nonce for the
package_app_actionAJAX endpoint. - The attacker identifies the target Administrator's user ID (often user ID 1 on default WordPress installations, or discoverable through author archives and the REST API).
- The attacker sends a single POST request to
wp-admin/admin-ajax.phpwith the following parameters:
| Field | Value | Purpose |
|---|---|---|
action (WordPress routing) | package_app_action | Routes to the plugin's AJAX handler |
action (plugin routing) | updateUser | Routes to Schedule::updateUser() |
user_id | Target Administrator's ID | Selects the victim account |
user_email | Attacker controlled email | Overwrites the victim's email |
user_pass | Attacker chosen password | Overwrites the victim's password |
- The dispatcher invokes
Schedule::updateUser()with$administrator = 1, bypassing the owner restriction check. - The function calls
wp_update_user()with the attacker supplied data, changing the Administrator's email and password. - The attacker logs in as the Administrator using the new credentials.
From this point, the attacker has full control of the WordPress installation: they can install plugins, modify themes, create additional accounts, access the database through plugins like WP DB Manager, or pivot to the hosting environment.
Why the Nonce Check Is Insufficient
A common misconception is that WordPress nonce verification provides authorization. It does not. Nonces in WordPress verify intent and protect against CSRF attacks, but they do not verify that the user has the capability to perform the requested action. An Editor level user will have a valid nonce for AJAX endpoints registered via wp_ajax_* hooks, which is sufficient to pass the nonce check in this handler. The missing piece is a current_user_can() check, which is what the patch in version 1.7.17 adds.
Affected Systems and Versions
| Version Range | Status |
|---|---|
| All versions up to and including 1.7.16 | Vulnerable |
| Version 1.7.17 | Patched |
The vulnerability affects any WordPress installation running the Booking Package plugin at version 1.7.16 or earlier where at least one user has Editor level access or above. The plugin is compatible with WordPress 3.5 and higher, tested up to WordPress 7.0.
Vendor Security History
The Booking Package plugin has a documented pattern of security vulnerabilities:
| CVE | Affected Versions | Patched Version | Type | CVSS |
|---|---|---|---|---|
| CVE-2024-30516 | <= 1.6.27 | 1.6.29 | Price Manipulation | 7.5 |
| CVE-2026-9851 | <= 1.7.16 | 1.7.17 | Privilege Escalation (CWE-639) | 7.2 |
The price manipulation vulnerability (CVE-2024-30516) was reported by researcher Abdi Pranata through Patchstack and published in March 2024. Both vulnerabilities involve insufficient authorization and input validation, suggesting that the plugin's development process does not include systematic security review of its AJAX surface and authorization patterns. Organizations relying on this plugin should weigh this track record when making risk decisions.
References
- NVD Entry for CVE-2026-9851
- CVE Record: CVE-2026-9851
- Wordfence Advisory: Booking Package 1.7.16 Authenticated (Editor+) Privilege Escalation via Account Takeover
- Wordfence: Booking Package Vulnerability History
- Vulnerable Code: index.php line 4416 (AJAX Entry Point)
- Vulnerable Code: index.php line 4477 (Dynamic Dispatch)
- Vulnerable Code: Schedule.php line 868 (updateUser Function)
- Patch Changeset 3558752
- Booking Package Plugin on WordPress.org
- CWE-639: Authorization Bypass Through User-Controlled Key
- Patchstack: CVE-2024-30516 Price Manipulation in Booking Package
- SAASPROJECT Developer Profile
- SaasProject Website



