CVE-2025-68042

Travelpayouts <= 1.2.1 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.2.1
PublishedJanuary 29, 2026
Last updatedFebruary 2, 2026
Affected plugintravelpayouts
Research Plan
Unverified

# 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 like tp_marker.
  • Authentication: Required (Subscriber level or higher).
  • Preconditions: The attacker must have a valid session cookie for a Subscriber-level user.

3. Code Flow

  1. Entry Point: The plugin registers AJAX actions in its main initialization or admin class. In Travelpayouts, this is typically handled within app/includes/TPAdmin.php or app/TPPlugin.php.
  2. Hook Registration:
    // Inferred registration
    add_action( 'wp_ajax_tp_save_settings', array( $this, 'tp_save_settings' ) );
    
  3. Vulnerable Function: The tp_save_settings function is called.
  4. 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:

  1. Identify Script Localization: Search for wp_localize_script in the plugin code to find the nonce key and variable name.
  2. Page Navigation: Navigate to the /wp-admin/index.php (Dashboard) as a Subscriber.
  3. Extraction:
    • JS Variable (Inferred): window.tp_admin_data?.nonce or window.TP_Admin?.nonce.
    • Action String (Inferred): tp_settings_action.
  4. Execution: Use browser_eval to extract the token:
    // Attempt to find localized data
    browser_eval("window.tp_admin_data?.nonce || window.TP_Admin?.nonce")
    
  5. Alternative: If no nonce is localized for Subscribers, check if the check_ajax_referer call is present at all. Many "Missing Authorization" bugs in this plugin category also neglect CSRF protection.

5. Exploitation Strategy

  1. Authentication: Log in to the target WordPress instance as a user with the Subscriber role.
  2. Nonce Extraction: Use browser_navigate to /wp-admin/ and browser_eval to grab the nonce if available.
  3. Craft Payload: Prepare a JSON or URL-encoded payload that modifies the tp_marker. The marker is the affiliate ID; changing it diverts commissions.
  4. HTTP Request:
    POST /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]
    
    Note: If the settings are stored as an array, the parameters might look like tp_settings[marker]=ATTACKER_ID_999.

6. Test Data Setup

  1. Install Plugin: Travelpayouts version 1.2.1.
  2. Configure Plugin: Set a "legitimate" marker ID (e.g., 12345) via the Admin panel.
  3. Create User: Create a user with the role subscriber.
  4. Identify Option Name: Confirm the option name used to store settings (usually travelpayouts_settings or tp_options).

7. Expected Results

  • The server should respond with a 200 OK and likely a JSON body like {"success": true}.
  • The tp_marker value in the database should be updated to the attacker's value (ATTACKER_ID_999).

8. Verification Steps

  1. 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
    
  2. 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_settings is not the correct action, grep for wp_ajax_ in the plugin source to identify all registered administrative actions and test each for missing current_user_can() checks.
  • REST API: Check if the plugin registers any REST routes via register_rest_route in rest_api_init. If it does, check the permission_callback. If it is __return_true or missing, exploitation can occur via /wp-json/.
  • Parameter Variation: If the POST request fails, try sending the payload as application/json or as a GET request (though admin-ajax.php usually expects POST for state changes).
Research Findings
Static analysis — not yet PoC-verified

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

--- a/app/includes/TPAdmin.php
+++ b/app/includes/TPAdmin.php
@@ -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.