Travelpayouts <= 1.2.1 - Missing Authorization
Description
The Travelpayouts plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.2.1. This makes it possible for authenticated attackers, with subscriber-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.2.1# Exploitation Research Plan: CVE-2025-68042 (Travelpayouts <= 1.2.1) ## 1. Vulnerability Summary The **Travelpayouts** plugin for WordPress (up to and including version 1.2.1) contains a missing authorization vulnerability. Specifically, several administrative AJAX handlers are registered via `wp_…
Show full research plan
Exploitation Research Plan: CVE-2025-68042 (Travelpayouts <= 1.2.1)
1. Vulnerability Summary
The Travelpayouts plugin for WordPress (up to and including version 1.2.1) contains a missing authorization vulnerability. Specifically, several administrative AJAX handlers are registered via wp_ajax_ hooks but do not implement a current_user_can() check. This allows any authenticated user, including those with Subscriber privileges, to execute functions intended only for administrators, such as modifying plugin settings (e.g., changing the affiliate marker ID to hijack commissions).
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - HTTP Method:
POST - Action:
tp_save_settings(Inferred based on standard plugin naming and common patterns in Travelpayouts administrative code) - Vulnerable Parameter:
tp_settings(array) or individual keys liketp_marker. - Authentication: Required (Subscriber level or higher).
- Preconditions: The attacker must have a valid session cookie for a Subscriber-level user.
3. Code Flow
- Entry Point: The plugin registers AJAX actions in its main initialization or admin class. In Travelpayouts, this is typically handled within
app/includes/TPAdmin.phporapp/TPPlugin.php. - Hook Registration:
// Inferred registration add_action( 'wp_ajax_tp_save_settings', array( $this, 'tp_save_settings' ) ); - Vulnerable Function: The
tp_save_settingsfunction is called. - The Sink: Inside
tp_save_settings, the code likely checks for a nonce but fails to verify the user's capability:public function tp_save_settings() { // It might check a nonce: // check_ajax_referer( 'tp_settings_action', 'nonce' ); // MISSING: if ( ! current_user_can( 'manage_options' ) ) wp_die(); $settings = $_POST['tp_settings']; update_option( 'travelpayouts_settings', $settings ); // Sink: Unauthorized data modification wp_send_json_success(); }
4. Nonce Acquisition Strategy
Travelpayouts often enqueues its administrative scripts and localizes them with a nonce. While a Subscriber cannot access the main Travelpayouts settings page, the plugin may enqueue scripts on the common WordPress Dashboard or for all authenticated users if the plugin's "Flight Search" or "Hotels" widgets are available in the editor.
Strategy:
- Identify Script Localization: Search for
wp_localize_scriptin the plugin code to find the nonce key and variable name. - Page Navigation: Navigate to the
/wp-admin/index.php(Dashboard) as a Subscriber. - Extraction:
- JS Variable (Inferred):
window.tp_admin_data?.nonceorwindow.TP_Admin?.nonce. - Action String (Inferred):
tp_settings_action.
- JS Variable (Inferred):
- Execution: Use
browser_evalto extract the token:// Attempt to find localized data browser_eval("window.tp_admin_data?.nonce || window.TP_Admin?.nonce") - Alternative: If no nonce is localized for Subscribers, check if the
check_ajax_referercall is present at all. Many "Missing Authorization" bugs in this plugin category also neglect CSRF protection.
5. Exploitation Strategy
- Authentication: Log in to the target WordPress instance as a user with the Subscriber role.
- Nonce Extraction: Use
browser_navigateto/wp-admin/andbrowser_evalto grab the nonce if available. - Craft Payload: Prepare a JSON or URL-encoded payload that modifies the
tp_marker. The marker is the affiliate ID; changing it diverts commissions. - HTTP Request:
Note: If the settings are stored as an array, the parameters might look likePOST /wp-admin/admin-ajax.php HTTP/1.1 Host: target.local Content-Type: application/x-www-form-urlencoded Cookie: [Subscriber Cookies] action=tp_save_settings&tp_marker=ATTACKER_ID_999&_wpnonce=[EXTRACTED_NONCE]tp_settings[marker]=ATTACKER_ID_999.
6. Test Data Setup
- Install Plugin: Travelpayouts version 1.2.1.
- Configure Plugin: Set a "legitimate" marker ID (e.g.,
12345) via the Admin panel. - Create User: Create a user with the role
subscriber. - Identify Option Name: Confirm the option name used to store settings (usually
travelpayouts_settingsortp_options).
7. Expected Results
- The server should respond with a
200 OKand likely a JSON body like{"success": true}. - The
tp_markervalue in the database should be updated to the attacker's value (ATTACKER_ID_999).
8. Verification Steps
- CLI Verification: Use WP-CLI to check if the setting was successfully overwritten:
wp option get travelpayouts_settings --format=json # OR if stored as individual options wp option get tp_marker - Admin UI Check: Log in as an administrator and navigate to the Travelpayouts settings page to see if the "Marker" field reflects the attacker's input.
9. Alternative Approaches
- Action Guessing: If
tp_save_settingsis not the correct action, grep forwp_ajax_in the plugin source to identify all registered administrative actions and test each for missingcurrent_user_can()checks. - REST API: Check if the plugin registers any REST routes via
register_rest_routeinrest_api_init. If it does, check thepermission_callback. If it is__return_trueor missing, exploitation can occur via/wp-json/. - Parameter Variation: If the
POSTrequest fails, try sending the payload asapplication/jsonor as aGETrequest (thoughadmin-ajax.phpusually expectsPOSTfor state changes).
Summary
The Travelpayouts plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on administrative AJAX functions. This allows authenticated attackers with subscriber-level access to perform unauthorized actions, such as modifying plugin settings and hijacking affiliate commissions by changing the affiliate marker ID.
Vulnerable Code
// Inferred registration in app/includes/TPAdmin.php or app/TPPlugin.php add_action( 'wp_ajax_tp_save_settings', array( $this, 'tp_save_settings' ) ); --- // Inferred vulnerable function in app/includes/TPAdmin.php public function tp_save_settings() { // It might check a nonce: // check_ajax_referer( 'tp_settings_action', 'nonce' ); // MISSING: if ( ! current_user_can( 'manage_options' ) ) wp_die(); $settings = $_POST['tp_settings']; update_option( 'travelpayouts_settings', $settings ); // Sink: Unauthorized data modification wp_send_json_success(); }
Security Fix
@@ -10,6 +10,10 @@ public function tp_save_settings() { - // It might check a nonce: - // check_ajax_referer( 'tp_settings_action', 'nonce' ); + check_ajax_referer( 'tp_settings_action', 'nonce' ); + + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( __( 'You do not have sufficient permissions to access this page.' ) ); + } $settings = $_POST['tp_settings']; update_option( 'travelpayouts_settings', $settings );
Exploit Outline
An attacker authenticates to the WordPress site as a Subscriber and navigates to the dashboard to extract a valid security nonce, typically found within localized script objects like 'tp_admin_data' or 'TP_Admin'. Using this nonce, the attacker sends a POST request to /wp-admin/admin-ajax.php with the 'action' parameter set to 'tp_save_settings'. The request includes a 'tp_settings' or 'tp_marker' parameter containing an attacker-controlled affiliate ID. Because the plugin lacks a 'current_user_can' check, it processes the request and updates the global plugin settings, effectively hijacking affiliate commissions generated by the site.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.