CVE-2026-12433

Hydra Booking <= 1.2.1 - Authenticated (Custom+) Insecure Direct Object Reference to Sensitive Information Exposure via 'booking_id' Parameter

mediumAuthorization Bypass Through User-Controlled Key
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.2.2
Patched in
1d
Time to patch

Description

The Hydra Booking – Appointment Scheduling & Booking Calendar plugin for WordPress is vulnerable to Insecure Direct Object Reference in versions up to, and including, 1.2.1 via the /wp-json/hydra-booking/v1/booking/details/{id} REST endpoint. This is due to the getBookingDetails() callback only enforcing the tfhb_manage_options capability via tfhb_manage_options_permission(), without verifying that the requested booking belongs to the currently authenticated host (the lookup in getBookingDetailsData() filters solely on the booking id supplied in the URL). This makes it possible for authenticated attackers, with Hydra Host-level access and above (a role created by the plugin which grants tfhb_manage_options), to view sensitive booking records belonging to other hosts, including attendee names, emails, phone numbers, addresses, meeting details, payment method and status, transaction history, and internal notes by iterating booking IDs.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Low
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=1.2.1
PublishedJuly 8, 2026
Last updatedJuly 9, 2026
Affected pluginhydra-booking

What Changed in the Fix

Changes introduced in v1.2.2

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-12433 (Hydra Booking IDOR) ## 1. Vulnerability Summary The **Hydra Booking** plugin for WordPress is vulnerable to an **Insecure Direct Object Reference (IDOR)** in its REST API. Specifically, the endpoint `/wp-json/hydra-booking/v1/booking/details/{id}` allow…

Show full research plan

Exploitation Research Plan: CVE-2026-12433 (Hydra Booking IDOR)

1. Vulnerability Summary

The Hydra Booking plugin for WordPress is vulnerable to an Insecure Direct Object Reference (IDOR) in its REST API. Specifically, the endpoint /wp-json/hydra-booking/v1/booking/details/{id} allows any user with the tfhb_host role to view the booking details of any other host.

While the plugin implements a permission check (tfhb_manage_options_permission) that restricts access to "Hosts," it fails to verify if the requested {id} belongs to the authenticated user. An attacker can iterate through booking IDs to expose sensitive attendee information, including names, emails, phone numbers, and meeting locations.

2. Attack Vector Analysis

  • Endpoint: /wp-json/hydra-booking/v1/booking/details/(?P<id>[0-9]+)
  • HTTP Method: GET
  • Authentication: Required. Any user with the tfhb_host role or the tfhb_manage_options capability.
  • Vulnerable Parameter: The id path variable in the URL.
  • Preconditions: The attacker must be logged in as a "Host" (a custom role created by the plugin).

3. Code Flow

  1. Route Registration: In admin/Controller/BookingController.php, the route is registered:
    register_rest_route(
        'hydra-booking/v1',
        '/booking/details/(?P<id>[0-9]+)',
        array(
            'methods'  => 'GET',
            'callback' => array( $this, 'getBookingDetails' ),
            'permission_callback' =>  array(new RouteController() , 'tfhb_manage_options_permission'),
        )
    );
    
  2. Permission Check: RouteController::tfhb_manage_options_permission verifies if the user has the tfhb_manage_options capability. This capability is granted to the tfhb_host role.
  3. Vulnerable Callback: The getBookingDetails callback (defined in BookingController.php) is executed. According to the vulnerability description, this function (and its helper getBookingDetailsData) retrieves booking data based purely on the id provided in the URL without checking the host_id against the current user's host ID.
  4. Existing (Unused) Protection: Note that BookingController contains a function tfhb_verify_booking_ownership( $booking_id ) (line 33) designed to check if a booking belongs to a host, but this function is not invoked in the permission_callback for the details endpoint.

4. Nonce Acquisition Strategy

The WordPress REST API requires a _wpnonce for authenticated requests to prevent CSRF, usually passed in the X-WP-Nonce header.

  1. Role Setup: The tfhb_host role is required.
  2. Dashboard Access: Logged-in hosts access the plugin via wp-admin/admin.php?page=hydra-booking.
  3. Nonce Extraction:
    • Navigate to http://localhost:8080/wp-admin/admin.php?page=hydra-booking.
    • The plugin likely localizes its settings. Common Hydra Booking localization variables include tfhb_admin_data.
    • Use browser_eval to extract the REST nonce from the standard WordPress wpApiSettings or the plugin-specific object.
    • Command: browser_eval("window.wpApiSettings?.nonce") or browser_eval("window.tfhb_admin_data?.nonce").

5. Exploitation Strategy

  1. Setup Phase:
    • Create a "Victim" user with the tfhb_host role.
    • Create an "Attacker" user with the tfhb_host role.
    • As the Victim, create a booking. Record the ID (e.g., 1).
  2. Execution Phase:
    • Authenticate as the Attacker.
    • Obtain a REST nonce (see Section 4).
    • Send a GET request to the target endpoint targeting the Victim's booking ID.
  3. Request Details:
    • Method: GET
    • URL: http://localhost:8080/wp-json/hydra-booking/v1/booking/details/[VICTIM_BOOKING_ID]
    • Headers:
      • X-WP-Nonce: [EXTRACTED_NONCE]
      • Content-Type: application/json

6. Test Data Setup

  1. Create Roles (if not automatic): Ensure the plugin is activated so it creates the tfhb_host role.
  2. Create Users:
    • wp user create victim victim@example.com --role=tfhb_host --user_pass=password
    • wp user create attacker attacker@example.com --role=tfhb_host --user_pass=password
  3. Seed Data:
    • Since the plugin uses custom tables (e.g., {$wpdb->prefix}tfhb_bookings), use the UI or wp db query to insert a booking for the Victim.
    • A booking requires a host_id. Ensure the Victim user has an entry in the tfhb_hosts table linked to their user_id.
    • Use the SetupWizard::CreateHost logic or manually link:
      wp db query "INSERT INTO wp_tfhb_hosts (user_id, email, status) VALUES ([VICTIM_UID], 'victim@example.com', 'activate')"
      wp db query "INSERT INTO wp_tfhb_bookings (host_id, status, meeting_title) VALUES ([VICTIM_HOST_ID], 'confirmed', 'Secret Strategy Meeting')"

7. Expected Results

  • The server returns a 200 OK response.
  • The JSON response body contains sensitive information:
    • meeting_title
    • attendee_details (Name, Email, etc.)
    • meeting_locations (Zoom links, addresses)
    • internal_notes

8. Verification Steps

  1. Check Response: Confirm the JSON contains the string "Secret Strategy Meeting" (or whatever title was seeded).
  2. Verify IDOR: Ensure the Attacker's own host ID is different from the Victim's host ID by checking the database:
    wp db query "SELECT id, user_id FROM wp_tfhb_hosts"

9. Alternative Approaches

If the details endpoint is patched or behaves differently, try other routes registered in BookingController::create_endpoint() that use the same permission_callback:

  • /booking/(?P<id>[0-9]+) (Calls getBookingData)
  • /booking/update-internal-note (POST request, may allow modification of other hosts' notes)
  • /booking/cancel-booking-attendee (POST request, may allow cancelling other hosts' meetings)

All these routes use tfhb_manage_options_permission and likely suffer from the same lack of ownership validation.

Research Findings
Static analysis — not yet PoC-verified

Summary

The Hydra Booking plugin for WordPress contains an Insecure Direct Object Reference (IDOR) vulnerability in its REST API. Authenticated attackers with the 'tfhb_host' role can access sensitive booking details of any user by manipulating the 'id' parameter in the /wp-json/hydra-booking/v1/booking/details/{id} endpoint, as the plugin fails to verify booking ownership.

Vulnerable Code

// admin/Controller/BookingController.php:125
		// Get Single Booking based on id
		register_rest_route(
			'hydra-booking/v1',
			'/booking/details/(?P<id>[0-9]+)',
			array(
				'methods'  => 'GET',
				'callback' => array( $this, 'getBookingDetails' ),
				'permission_callback' =>  array(new RouteController() , 'tfhb_manage_options_permission'),
			)
		);

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/hydra-booking/1.2.1/admin/Controller/BookingController.php	2026-06-28 07:15:40.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/hydra-booking/1.2.2/admin/Controller/BookingController.php	2026-07-08 10:48:44.000000000 +0000
@@ -900,6 +900,9 @@
 		$booking = new Booking();
 
 		if ( ! empty( $request['id'] ) ) {
+			if ( ! $this->tfhb_verify_booking_ownership( $request['id'] ) ) {
+				return new \WP_Error( 'rest_forbidden', __( 'You are not allowed to access this booking.', 'hydra-booking' ), array( 'status' => 403 ) );
+			}
 			$data = array(
 				'id'                 => isset( $request['id'] ) ? $request['id'] : '',
 				'meeting_id'         => isset( $request['meeting'] ) ? $request['meeting'] : '',
@@ -998,6 +1001,11 @@
 				)
 			);
 		}
+
+		if ( ! $this->tfhb_verify_booking_ownership( $booking_id ) ) {
+			return new \WP_Error( 'rest_forbidden', __( 'You are not allowed to access this booking.', 'hydra-booking' ), array( 'status' => 403 ) );
+		}
+
 		// Delete Booking
 		$booking       = new Booking();
 		$single_booking_meta = $booking->get( absint( $booking_id ) );
@@ -1160,6 +1168,10 @@
 			);
 		}
 
+		if ( ! $this->tfhb_verify_booking_ownership( $attendeeBooking->booking_id ) ) {
+			return new \WP_Error( 'rest_forbidden', __( 'You are not allowed to access this booking.', 'hydra-booking' ), array( 'status' => 403 ) );
+		}
+
 		if( 'confirmed' != $attendeeBooking->status ){
 			return rest_ensure_response(
 				array(
@@ -1217,6 +1229,11 @@
 				)
 			);
 		}
+
+		if ( ! $this->tfhb_verify_booking_ownership( $attendeeBooking->booking_id ) ) {
+			return new \WP_Error( 'rest_forbidden', __( 'You are not allowed to access this booking.', 'hydra-booking' ), array( 'status' => 403 ) );
+		}
+
 		if($attendeeBooking->status == $status){
 			return rest_ensure_response(
 				array(
@@ -1667,6 +1684,10 @@
 			);
 		}
 
+		if ( ! $this->tfhb_verify_booking_ownership( $booking_id ) ) {
+			return new \WP_Error( 'rest_forbidden', __( 'You are not allowed to access this booking.', 'hydra-booking' ), array( 'status' => 403 ) );
+		}
+
 		$data = array(
 			'id'     => $request['id'],
 			'status' => isset( $request['status'] ) ? sanitize_text_field( $request['status'] ) : '',
@@ -1762,6 +1783,8 @@
 		$items    = $request['items'];
 		$booking_owner = !empty($request['host']) ? $request['host'] : '';
 
+		// Only keep booking ids the current user is actually allowed to touch.
+		$items = ! empty( $items ) ? array_values( array_filter( $items, array( $this, 'tfhb_verify_booking_ownership' ) ) ) : $items;

Exploit Outline

1. Gain access to a WordPress account with the 'tfhb_host' role (or any role possessing the 'tfhb_manage_options' capability). 2. Obtain a valid WordPress REST API nonce (typically found in the 'wpApiSettings' or 'tfhb_admin_data' JavaScript objects on the plugin's dashboard). 3. Identify a target booking ID belonging to another host. 4. Send an authenticated GET request to `/wp-json/hydra-booking/v1/booking/details/{id}`, replacing `{id}` with the target booking ID and including the nonce in the 'X-WP-Nonce' header. 5. The server will respond with the full details of the booking, including attendee PII (name, email, phone) and internal host notes.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.