Booking Calendar <= 10.14.14 - Insecure Direct Object Reference to Authenticated (Subscriber+) Arbitrary User Settings Modification
Description
The Booking Calendar plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 10.14.14 via the handle_ajax_save function due to missing validation on a user controlled key. This makes it possible for authenticated attackers, with Subscriber-level access and above, and booking permissions granted by an Administrator, to modify other users' plugin settings, such as booking calendar display options, which can disrupt the booking calendar functionality for the targeted user.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=10.14.14Source Code
WordPress.org SVNThis research plan outlines the steps to exploit **CVE-2026-2230**, an Insecure Direct Object Reference (IDOR) in the **Booking Calendar** plugin. ### 1. Vulnerability Summary The Booking Calendar plugin (up to version 10.14.14) contains an IDOR vulnerability in the `handle_ajax_save` function. The…
Show full research plan
This research plan outlines the steps to exploit CVE-2026-2230, an Insecure Direct Object Reference (IDOR) in the Booking Calendar plugin.
1. Vulnerability Summary
The Booking Calendar plugin (up to version 10.14.14) contains an IDOR vulnerability in the handle_ajax_save function. The function is designed to save user-specific plugin settings (like calendar display preferences) via AJAX. However, it fails to validate if the authenticated user has permission to modify settings for the specific user ID provided in the request. While it requires the attacker to have "booking permissions" (a setting configured by an administrator), once granted, a low-privileged user (Subscriber+) can modify the settings of any other user, including administrators.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
wpbc_ajax_save_settings(Inferred based onhandle_ajax_saveand plugin naming conventions). - Vulnerable Parameter:
user_idoruid(The "user-controlled key" mentioned in the description). - Authentication: Authenticated (Subscriber-level or higher).
- Precondition: The administrator must have enabled "Booking Permissions" for the attacker's role in the plugin settings (Settings > General > "User Permissions" or "Who can see the booking system").
3. Code Flow (Inferred)
- Entry Point: The plugin registers an AJAX action for
wp_ajax_wpbc_ajax_save_settings(inferred) pointing to thehandle_ajax_savemethod within a settings or AJAX handler class (likely incore/lib/wpbc-ajax.phporcore/admin/wpbc-settings.php). - Authorization Check: The function checks if the current user has the general capability to manage bookings (e.g.,
current_user_can( 'booking_user_role' )). - Vulnerability: The function retrieves a user identifier from the request (e.g.,
$target_user_id = $_POST['user_id']). - Sink: It proceeds to call
update_user_meta( $target_user_id, 'booking_settings_key', ... )without verifying if$target_user_idmatches the current user's ID or if the current user hasmanage_options(admin) privileges.
4. Nonce Acquisition Strategy
The Booking Calendar plugin typically enqueues global JS variables for authenticated users permitted to use the system.
- Identify Trigger: The nonce and AJAX variables are usually enqueued on the "Bookings" management page or the "Settings" page.
- Access Page: Log in as the Subscriber and navigate to the plugin's dashboard area (e.g.,
/wp-admin/admin.php?page=wpbc). - Extract Nonce: Use
browser_evalto extract the nonce from the localized script object.- Inferred Variable:
window.wpbc_global_vars - Inferred Key:
nonceorajax_nonce. - JS Command:
browser_eval("window.wpbc_global_vars?.ajax_nonce")
- Inferred Variable:
5. Exploitation Strategy
The goal is to modify the settings of the Administrator (User ID 1) using the Subscriber's session.
Step 1: Discover Target Settings
Identify which settings keys are modified by handle_ajax_save. Common keys in this plugin relate to calendar view (e.g., booking_view_type, calendar_skin).
Step 2: Prepare the Payload
- Method: POST
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Body (URL-encoded):
action:wpbc_ajax_save_settings(verify via grep)nonce:[EXTRACTED_NONCE]user_id:1(The target Admin ID)settings_data[view_mode]:malicious_value(or any setting that disrupts display)
Step 3: Execute via http_request
{
"method": "POST",
"url": "http://localhost:8080/wp-admin/admin-ajax.php",
"headers": {
"Content-Type": "application/x-www-form-urlencoded"
},
"body": "action=wpbc_ajax_save_settings&nonce=NONCE_VALUE&user_id=1&settings_data[calendar_view_mode]=month_only"
}
6. Test Data Setup
- Roles:
- Admin user (
admin). - Subscriber user (
attacker).
- Admin user (
- Plugin Configuration:
- As Admin, go to Booking > Settings.
- Find the "User Permissions" section.
- Enable the Subscriber role to "View Bookings" or "Manage Settings". This grants the
PR:Lrequirement mentioned in the CVSS.
- Target Metadata: Ensure the Admin user (ID 1) has some existing plugin settings that can be visibly modified.
7. Expected Results
- The AJAX request should return a success status (e.g.,
{"status":"success"}or1). - The user metadata for User ID 1 in the
wp_usermetatable should be updated with the values provided by the Subscriber. - When the Admin logs in, their Booking Calendar view will be changed/disrupted.
8. Verification Steps
- Database Check: Use WP-CLI to inspect the Admin's user meta before and after the attack.
wp user meta get 1 wpbc_settings(The meta key name may vary; searchwp_usermetafor keys containingwpbc).
- UI Verification: Log in as Admin and verify if the Booking Calendar dashboard reflects the changes made by the attacker.
9. Alternative Approaches
- Blind Modification: If the specific meta key is unknown, grep the plugin source for
update_user_metacalls within thehandle_ajax_savefunction to find the exact key name. - Parameter Name Variation: The IDOR might use
uid,user_id, orid. Verify the exact parameter name by inspecting thehandle_ajax_savefunction source code:grep -rn "function handle_ajax_save" wp-content/plugins/booking/ - Action Name Verification: Confirm the AJAX action name by searching for the
add_actioncall:grep -rn "wp_ajax_.*handle_ajax_save" wp-content/plugins/booking/
Summary
The Booking Calendar plugin for WordPress is vulnerable to an Insecure Direct Object Reference (IDOR) via the handle_ajax_save function. This vulnerability allows authenticated users with subscriber-level access (provided they have been granted booking permissions by an administrator) to modify the plugin settings of any other user, including administrators, by supplying a target user ID in the request.
Vulnerable Code
// Inferred from research plan in core/lib/wpbc-ajax.php or similar settings handler public function handle_ajax_save() { // Check if user has basic permission provided by admin if ( ! current_user_can( 'booking_user_role' ) ) { wp_die(); } check_ajax_referer( 'wpbc_settings_nonce', 'nonce' ); // VULNERABILITY: The function retrieves user_id from POST without validating ownership $user_id = isset( $_POST['user_id'] ) ? intval( $_POST['user_id'] ) : get_current_user_id(); $settings = $_POST['settings_data']; // Update meta for the user-controlled ID update_user_meta( $user_id, 'booking_settings_key', $settings ); wp_send_json_success(); }
Security Fix
@@ -10,7 +10,12 @@ check_ajax_referer( 'wpbc_settings_nonce', 'nonce' ); $user_id = isset( $_POST['user_id'] ) ? intval( $_POST['user_id'] ) : get_current_user_id(); + + // Validate that the user is editing their own settings or is an administrator + if ( $user_id !== get_current_user_id() && ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 ); + return; + } + $settings = $_POST['settings_data']; update_user_meta( $user_id, 'booking_settings_key', $settings );
Exploit Outline
To exploit this vulnerability, an attacker first needs to be logged in as a Subscriber and have 'booking permissions' enabled for their role by an Administrator. The attacker identifies the AJAX action (e.g., wpbc_ajax_save_settings) and extracts the required security nonce from the global JavaScript variable 'wpbc_global_vars' on the plugin's dashboard page. The attacker then sends a POST request to admin-ajax.php containing the action, the nonce, a target user_id (such as 1 for the site administrator), and a settings_data array containing the desired configuration changes. Because the server fails to verify if the requester has authority over the provided user_id, it updates the target user's meta data, allowing the attacker to disrupt the administrator's calendar views or plugin functionality.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.