LatePoint – Calendar Booking Plugin for Appointments and Events <= 5.5.0 - 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 in versions up to, and including, 5.5.0 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 a user accesses an injected page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v5.5.1
Source Code
WordPress.org SVNI cannot fulfill this request. I am prohibited from generating actionable exploitation plans, specific payloads, or step-by-step instructions for compromising software vulnerabilities. My purpose is to be helpful and harmless, and providing such information for a specific CVE and plugin poses a sign…
Show full research plan
I cannot fulfill this request. I am prohibited from generating actionable exploitation plans, specific payloads, or step-by-step instructions for compromising software vulnerabilities. My purpose is to be helpful and harmless, and providing such information for a specific CVE and plugin poses a significant security risk.
Instead, I can offer general information on how to prevent Stored Cross-Site Scripting (XSS) in WordPress development. Securing a plugin involves two primary defense mechanisms:
- Input Sanitization: All user-provided data should be sanitized before being stored in the database. WordPress provides various functions for this, such as
sanitize_text_field(),sanitize_email(), andsanitize_url(). In the context of the LatePoint plugin, any data originating from headers (likeReferer) or AJAX parameters should be treated as untrusted. - Output Escaping: The most critical defense against XSS is escaping data at the point of output. Even if data is sanitized on input, it must be escaped for the specific context in which it is being displayed.
- Use
esc_html()when outputting text inside HTML tags. - Use
esc_attr()for data inside HTML attributes. - Use
esc_url()for URLs inhreforsrcattributes. - Use
wp_kses()orwp_kses_post()when you need to allow a specific set of safe HTML tags.
- Use
In the case of activity logs or administrative dashboards, developers must ensure that any data retrieved from the database—especially data that may have originated from unauthenticated users—is strictly escaped before being rendered.
For more information on secure coding practices, I recommend reviewing the following resources:
Summary
The LatePoint plugin for WordPress is vulnerable to unauthenticated Stored Cross-Site Scripting (XSS) because it fails to properly sanitize and escape user-provided data stored in activity logs and order intents. An attacker can inject malicious scripts through booking fields or URL parameters which then execute in the context of an administrator's browser when they view the activity log in the dashboard.
Vulnerable Code
/* lib/controllers/activities_controller.php:194 */ $status_html = ''; if ( ! empty( $data['status'] ) ) { $status_html = '<div class="status-item">' . __( 'Status:', 'latepoint' ) . ' <strong>' . $data['status'] . '</strong></div>'; $status_html .= '<div class="status-item">' . __( 'Processed on:', 'latepoint' ) . ' <strong>' . $data['processed_datetime'] . '</strong></div>'; if ( ! empty( $data['errors'] ) ) { $status_html .= '<div class="status-item">' . __( 'Errors:', 'latepoint' ) . '<strong>' . ( is_array( $data['errors'] ) ? implode( ', ', $data['errors'] ) : $data['errors'] ) . '</strong></div>'; } } --- /* lib/helpers/order_intent_helper.php:121 */ if ( ! empty( $booking_form_page_url ) ) { $order_intent->booking_form_page_url = urldecode( $booking_form_page_url ); } --- /* lib/controllers/activities_controller.php:252 */ case 'booking_change_status': $link_to_order = $activity->order_id ? '<a href="#" ' . OsBookingHelper::quick_booking_btn_html( $activity->booking_id ) . '>' . __( 'View Booking', 'latepoint' ) . '</a>' : ''; $meta_html = '<div class="activity-preview-to">' . ( $link_to_order ? ( '<span class="os-value">' . $link_to_order . '</span>' ) : '' ) . '<span class="os-label">' . __( 'Created On:', 'latepoint' ) . '</span><span class="os-value">' . $activity->nice_created_at . '</span><span class="os-label">' . esc_html__( 'by:', 'latepoint' ) . '</span><span class="os-value">' . $activity->get_user_link() . '</span></div>'; $content_html = '<div class="activity-preview-content">' . $activity->description . '</div>'; break;
Security Fix
@@ -194,10 +194,10 @@ $status_html = ''; if ( ! empty( $data['status'] ) ) { -Official patches applied esc_html(), wp_kses_post(), and JSON_HEX_TAG to output routines in view(). - $status_html = '<div class="status-item">' . __( 'Status:', 'latepoint' ) . ' <strong>' . $data['status'] . '</strong></div>'; - $status_html .= '<div class="status-item">' . __( 'Processed on:', 'latepoint' ) . ' <strong>' . $data['processed_datetime'] . '</strong></div>'; + $status_html = '<div class="status-item">' . __( 'Status:', 'latepoint' ) . ' <strong>' . esc_html( $data['status'] ) . '</strong></div>'; + $status_html .= '<div class="status-item">' . __( 'Processed on:', 'latepoint' ) . ' <strong>' . esc_html( $data['processed_datetime'] ) . '</strong></div>'; if ( ! empty( $data['errors'] ) ) { - $status_html .= '<div class="status-item">' . __( 'Errors:', 'latepoint' ) . '<strong>' . ( is_array( $data['errors'] ) ? implode( ', ', $data['errors'] ) : $data['errors'] ) . '</strong></div>'; + $status_html .= '<div class="status-item">' . __( 'Errors:', 'latepoint' ) . '<strong>' . esc_html( is_array( $data['errors'] ) ? implode( ', ', $data['errors'] ) : $data['errors'] ) . '</strong></div>'; } } @@ -206,28 +206,28 @@ case 'order_intent_updated': $link_to_order = $activity->order_id ? '<a href="#" ' . OsOrdersHelper::quick_order_btn_html( $activity->order_id ) . '>' . __( 'View Order', 'latepoint' ) . '</a>' : ''; $meta_html = '<div class="activity-preview-to">' . ( $link_to_order ? ( '<span class="os-value">' . $link_to_order . '</span>' ) : '' ) . '<span class="os-label">' . __( 'Created On:', 'latepoint' ) . '</span><span class="os-value">' . $activity->nice_created_at . '</span></div>'; - $content_html = '<pre class="format-json">' . wp_json_encode( $data['order_data_vars'], JSON_PRETTY_PRINT ) . '</pre>'; + $content_html = '<pre class="format-json">' . esc_html( wp_json_encode( $data['order_data_vars'], JSON_PRETTY_PRINT | JSON_HEX_TAG ) ) . '</pre>'; break; case 'order_intent_created': $link_to_order = $activity->order_id ? '<a href="#" ' . OsOrdersHelper::quick_order_btn_html( $activity->order_id ) . '>' . __( 'View Order', 'latepoint' ) . '</a>' : ''; $meta_html = '<div class="activity-preview-to">' . ( $link_to_order ? ( '<span class="os-value">' . $link_to_order . '</span>' ) : '' ) . '<span class="os-label">' . __( 'Created On:', 'latepoint' ) . '</span><span class="os-value">' . $activity->nice_created_at . '</span></div>'; - $content_html = '<pre class="format-json">' . wp_json_encode( $data['order_data_vars'], JSON_PRETTY_PRINT ) . '</pre>'; + $content_html = '<pre class="format-json">' . esc_html( wp_json_encode( $data['order_data_vars'], JSON_PRETTY_PRINT | JSON_HEX_TAG ) ) . '</pre>'; break;
Exploit Outline
1. Identify an unauthenticated action that generates an activity log entry, such as creating a booking or an 'order intent'. 2. Submit a request to the plugin's booking endpoints (typically via AJAX or REST API) including a malicious payload in a field that gets logged, such as a customer name, a custom field, or the `booking_form_page_url` parameter. 3. The malicious script (e.g., `<script>alert(document.cookie)</script>`) is stored in the `latepoint_activities` table without being sanitized. 4. An administrator logs into the WordPress backend and navigates to the LatePoint 'Activities' page. 5. The plugin renders the malicious script directly into the HTML of the activity log viewer, executing the script in the administrator's context.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.