Introduction
A missing capability check in the WordPress Booking Package plugin lets any Editor level user hijack Administrator accounts with a single AJAX request, turning a common content management role into full site control. With over 10,000 active installations, the flaw reaches a meaningful slice of small and medium business WordPress deployments that use 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 inside WordPress. It has been available since February 2018 and is marketed as a free solution with premium features, aimed at businesses that need booking 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. It affects versions up to and including 1.7.16 of the Booking Package plugin.
Root Cause: Three Layers of Missing Authorization
The vulnerability comes from three connected failures in the plugin's authorization architecture. Each layer trusts the one above it without doing its own validation, which leaves defense in depth broken all the way down.
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 creates a booking_package_schedule object and reads the $_POST['action'] parameter to decide which method to call. At this point the handler checks only a WordPress nonce. It never checks whether the requesting user has the edit_users capability or any privilege beyond basic authentication.
Layer 2: Unsafe Dynamic Dispatch (index.php, line 4477)
The dispatcher at line 4477 runs a dynamic method call using the client controlled $_POST['action'] value. When action=updateUser is supplied, the request routes straight to Schedule::updateUser(). There is no whitelist of permitted actions, no role verification, and no call to current_user_can() before the dispatch happens. 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 takes a $data array (containing the target user ID, email, password, and role) along with an $administrator boolean parameter. That $administrator parameter is the only authorization gate inside the function: when it is true, the function skips its owner restriction check and passes every supplied field, including role, straight to wp_update_user().
The critical flaw is that the dispatcher hard codes $administrator to 1 when it calls this function. The authorization gate is therefore always open, no matter what privileges the requesting user actually holds. The target user is chosen entirely from attacker supplied input.
Attack Flow
An authenticated attacker with Editor level access exploits the flaw through this sequence:
- The attacker authenticates to WordPress with an Editor account and gets a valid nonce for the
package_app_actionAJAX endpoint. - The attacker finds 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 these 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 calls
Schedule::updateUser()with$administrator = 1, skipping 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 here the attacker has full control of the WordPress installation. They can install plugins, modify themes, create more accounts, reach the database through plugins like WP DB Manager, or pivot to the hosting environment.
Why the Nonce Check Is Insufficient
It is a common mistake to think WordPress nonce verification provides authorization. It does not. Nonces verify intent and protect against CSRF attacks, but they do not verify that the user can perform the requested action. An Editor level user holds a valid nonce for AJAX endpoints registered via wp_ajax_* hooks, which is enough 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 flaw 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 flaw (CVE-2024-30516) was reported by researcher Abdi Pranata through Patchstack and published in March 2024. Both bugs involve weak authorization and input validation, which suggests the plugin's development process does not include systematic security review of its AJAX surface and authorization patterns. Organizations that rely on this plugin should weigh that track record when they make 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



