LatePoint – Calendar Booking Plugin for Appointments and Events <= 5.2.6 - Missing Authorization to Booking Details Exposure
Description
The LatePoint – Calendar Booking Plugin for Appointments and Events plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on the load_step() function in all versions up to, and including, 5.2.6. This makes it possible for unauthenticated attackers to view booking information including customer names, email addresses, phone numbers, appointment times, and service details.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:NTechnical Details
<=5.2.6Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-1537 - LatePoint Booking Details Exposure ## 1. Vulnerability Summary The LatePoint plugin (<= 5.2.6) contains a missing authorization vulnerability within its AJAX routing system, specifically targeting the `load_step()` function. The plugin uses a custom rou…
Show full research plan
Exploitation Research Plan: CVE-2026-1537 - LatePoint Booking Details Exposure
1. Vulnerability Summary
The LatePoint plugin (<= 5.2.6) contains a missing authorization vulnerability within its AJAX routing system, specifically targeting the load_step() function. The plugin uses a custom routing mechanism where requests are funneled through a central AJAX handler. The load_step method, intended to transition users through the booking wizard steps, fails to validate whether the requester has permission to view the details of a specific booking_id. Consequently, an unauthenticated attacker can supply a booking ID and retrieve sensitive information including customer names, email addresses, phone numbers, and appointment specifics.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Actions:
latepoint_route_call(authenticated) andwp_ajax_nopriv_latepoint_route_call(unauthenticated). - Vulnerable Route:
bookings__load_step(Inferred from LatePoint'scontroller__actionrouting convention). - Payload Parameter:
booking_idoridpassed viaPOST. - Authentication: None required (unauthenticated).
- Preconditions: At least one booking must exist in the system for data to be exposed.
3. Code Flow
- Entry Point: An unauthenticated user sends a POST request to
admin-ajax.phpwithaction=latepoint_route_call. - Routing: The request is handled by
OsRouterHelper::route(). LatePoint parses therouteparameter (e.g.,bookings__load_step). - Controller Dispatch: The router instantiates
OsBookingsControllerand calls theload_step()method. - Vulnerable Logic (Inferred):
load_step()retrieves thebooking_idfrom the$_POSTor$_GETarray.- It fetches the booking object:
$booking = new OsBookingModel($booking_id);. - It determines which step to display (often the "verify" or "confirmation" step).
- The Flaw: The code lacks a check such as
if ($booking->customer_id != $current_customer_id && !current_user_can('manage_options')).
- Data Sink: The controller renders a template (view) containing the booking details and returns it as a JSON response or raw HTML.
4. Nonce Acquisition Strategy
LatePoint typically uses a localized JavaScript object to manage its AJAX operations.
- Identify the Script: The plugin enqueues its core JS on pages containing the booking shortcode.
- Shortcode:
[latepoint_book_button]or[latepoint_booking_form]. - Strategy:
- Create a public page with the shortcode:
wp post create --post_type=page --post_status=publish --post_title="Booking" --post_content='[latepoint_booking_form]'. - Navigate to this page.
- Extract the nonce from the
latepoint_helperorlatepoint_wizard_varsobject.
- Create a public page with the shortcode:
- JS Verification: Use
browser_evalto find the nonce:browser_eval("window.latepoint_helper?.latepoint_token")(Inferred identifier).- Note: If the plugin allows unauthenticated routing without a nonce for the wizard (common in booking plugins to avoid session expiration issues), the request may work with an empty or omitted nonce.
5. Exploitation Strategy
The goal is to request the "verify" step for a known or guessed booking ID.
- Request Method:
POST - URL:
http://<target>/wp-admin/admin-ajax.php - Content-Type:
application/x-www-form-urlencoded - Payload:
(Note:action=latepoint_route_call&route=bookings__load_step&id=<BOOKING_ID>&step_name=verifystep_namemight also becontact,payment, orconfirmationdepending on the exact version's view names.)
Step-by-Step Plan:
- Setup Data: Ensure a booking exists (see Test Data Setup).
- Extract Nonce: (If required) Navigate to the page with the shortcode and extract the token.
- Perform Attack: Use
http_requestto call the route with an incrementalid. - Capture Response: Analyze the
htmlordatafield in the JSON response for PII strings (Email, Phone, Name).
6. Test Data Setup
To simulate a populated environment:
- Create a Customer:
wp eval "if(!class_exists('OsCustomerModel')) { /* load plugin */ } $customer = new OsCustomerModel(); $customer->set_variables(['first_name' => 'Vulnerable', 'last_name' => 'User', 'email' => 'victim@example.com'])->save();" - Create a Booking:
wp eval "$booking = new OsBookingModel(); $booking->set_variables(['customer_id' => 1, 'service_id' => 1, 'agent_id' => 1, 'start_date' => '2026-01-01', 'start_time' => 600, 'end_time' => 660, 'status' => 'approved'])->save();" - Publish Booking Page:
wp post create --post_type=page --post_status=publish --post_title="Book" --post_content='[latepoint_booking_form]'
7. Expected Results
- Status Code: 200 OK.
- Response Body: A JSON object containing an
htmlkey. - Evidence: Inside the
htmlstring, look for:<span class="value">victim@example.com</span>- Specific customer labels like
latepoint-customer-info. - The booking ID and date/time.
8. Verification Steps
After the exploit attempt, verify the data matches the database:
- Check the booking ID used in the exploit:
wp db query "SELECT * FROM wp_latepoint_bookings WHERE id = <ID>" - Compare the output email/name with the values returned in the
http_requestresponse.
9. Alternative Approaches
- Route Variation: If
bookings__load_stepis restricted, trybookings__print_order_confirmationorbookings__get_customer_details. - Parameter Variation: Try
booking_idinstead ofid. - Direct View Access: LatePoint sometimes allows direct template loading via
latepoint_get_template_part. Check if theverifystep template can be loaded directly through the router. - ID Brute Forcing: Since booking IDs are sequential integers, script a loop to iterate from 1 to 100 to demonstrate mass exposure.
Summary
The LatePoint plugin for WordPress (<= 5.2.6) suffers from an insecure direct object reference (IDOR) vulnerability in its AJAX routing system. Unauthenticated attackers can supply a booking ID to the `load_step` action and retrieve sensitive booking information, including customer names, emails, and phone numbers, because the plugin fails to verify if the requester is authorized to view the specific booking.
Vulnerable Code
// lib/controllers/bookings_controller.php public function load_step() { $booking_id = $this->get_param('id'); $booking = new OsBookingModel($booking_id); // Vulnerability: No authorization check to ensure the current user // is either an admin or the owner of the booking. $this->vars['booking'] = $booking; $this->format_render(__FUNCTION__); }
Security Fix
@@ -102,6 +102,11 @@ public function load_step() { $booking_id = $this->get_param('id'); $booking = new OsBookingModel($booking_id); + + if (!OsAuthHelper::is_admin_logged_in() && !OsAuthHelper::is_current_customer($booking->customer_id)) { + wp_send_json_error(['message' => 'Unauthorized']); + return; + } + $this->vars['booking'] = $booking; $this->format_render(__FUNCTION__); }
Exploit Outline
1. Identify a WordPress site running LatePoint <= 5.2.6. 2. Locate the AJAX endpoint at `/wp-admin/admin-ajax.php`. 3. Identify the required action (usually `latepoint_route_call`) and potentially extract a nonce from the source of a page containing a booking shortcode (e.g., `latepoint_helper.latepoint_token`). 4. Craft a POST request to the AJAX endpoint with the following parameters: `action=latepoint_route_call`, `route=bookings__load_step`, `id=[TARGET_BOOKING_ID]`, and `step_name=verify` (or `confirmation`). 5. Submit the request unauthenticated. Since booking IDs are typically sequential integers, an attacker can iterate through IDs to scrape data. 6. The server response will contain a JSON object with an `html` field containing the rendered template for the requested step, which includes PII such as customer names, email addresses, and phone numbers.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.