WpTravelly <= 2.1.7 - Missing Authorization
Description
The WpTravelly plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.1.7. 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
<=2.1.7Source Code
WordPress.org SVNPatched version not available.
This research plan targets **CVE-2026-39565**, a Missing Authorization vulnerability in the **Travelly – Tour & Hotel Booking Solution** (slug: `tour-booking-manager`) plugin for WordPress. ### 1. Vulnerability Summary The WpTravelly plugin (<= 2.1.7) fails to perform capability checks (e.g., `curr…
Show full research plan
This research plan targets CVE-2026-39565, a Missing Authorization vulnerability in the Travelly – Tour & Hotel Booking Solution (slug: tour-booking-manager) plugin for WordPress.
1. Vulnerability Summary
The WpTravelly plugin (<= 2.1.7) fails to perform capability checks (e.g., current_user_can('manage_options')) on certain AJAX handlers registered via wp_ajax_. While these handlers are only available to authenticated users, the lack of a capability check allows users with the lowest privileges (Subscribers) to execute administrative actions. The most likely targets are functions related to saving plugin configurations or modifying tour/hotel data.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Vulnerable Action:
wptravelly_save_settings_data(inferred based on plugin architecture) orwptravelly_save_general_settings_data(inferred). - HTTP Method:
POST - Authentication: Authenticated, Subscriber-level or above.
- Payload Parameter:
settings_data(usually containing an array of plugin options) or specific setting keys. - Preconditions: The attacker must be logged in as a Subscriber. A valid AJAX nonce is likely required, even if authorization is missing.
3. Code Flow (Inferred)
- Entry Point: The plugin registers AJAX hooks in
includes/admin/class-admin-ajax.phporinc/admin/class-admin.php(inferred) using:add_action( 'wp_ajax_wptravelly_save_settings_data', array( $this, 'wptravelly_save_settings_data' ) ); - Request Handling: The
wptravelly_save_settings_datafunction is called when a POST request hitsadmin-ajax.phpwithaction=wptravelly_save_settings_data. - Vulnerable Code: Inside the function, the developer likely checks the nonce using
check_ajax_referer()but fails to checkcurrent_user_can(). - Sink: The function proceeds to update the WordPress
optionstable usingupdate_option()orupdate_post_meta()based on the user-provided$_POSTdata.
4. Nonce Acquisition Strategy
The plugin likely localizes a nonce for its admin interface. Since the vulnerability requires "Authenticated" access, we can extract the nonce from the WordPress dashboard after logging in as a Subscriber.
- Identify Localization: Look for
wp_localize_scriptin the plugin source (likely inincludes/admin/class-admin.php). - Target Variable: Look for a JS object named
wptravelly_ajax_objortour_booking_params. - Extraction Path:
- Create a Subscriber user and log in.
- Navigate to the WordPress Dashboard (
/wp-admin/). - Use
browser_evalto extract the nonce:browser_eval("window.wptravelly_ajax_obj?.nonce")orbrowser_eval("window.wptravelly_ajax_obj?.wptravelly_nonce").
- Action Check: Verify if the nonce action matches the verification action (e.g.,
wptravelly_ajax_nonce).
5. Exploitation Strategy
We will attempt to modify a plugin setting (e.g., changing the tour listing page or a contact email) to demonstrate unauthorized data modification.
Step 1: Setup Authentication
- Log in as a Subscriber user using the
browser_navigateandbrowser_type/clicktools.
Step 2: Nonce Extraction
- Navigate to
/wp-admin/and execute thebrowser_evalmentioned in Section 4.
Step 3: Unauthorized Request
- Send a
POSTrequest to/wp-admin/admin-ajax.phpusing thehttp_requesttool.
Payload Example:
POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=wptravelly_save_settings_data&nonce=[EXTRACTED_NONCE]&settings_data[tour_page_id]=1337&settings_data[booking_email]=attacker@example.com
6. Test Data Setup
- Install Plugin: Ensure
tour-booking-managerversion 2.1.7 is active. - Create Attacker:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123. - Initial State: Record the current value of the targeted setting:
wp option get wptravelly_settings(Note: Settings may be stored in a serialized array).
7. Expected Results
- Response: The server returns a
200 OKor a JSON success message (e.g.,{"success":true}). - Data Change: The targeted plugin setting in the database is updated despite the request coming from a Subscriber.
8. Verification Steps
- Database Check: Run
wp option get wptravelly_settingsvia WP-CLI. - Value Comparison: Verify that
tour_page_idis now1337or thebooking_emailmatches the payload. - UI Verification: Log in as Admin and navigate to the plugin settings page to see if the changes are reflected in the UI.
9. Alternative Approaches
If wptravelly_save_settings_data is not the correct action:
- Grep for Actions: Run
grep -r "wp_ajax_" wp-content/plugins/tour-booking-manager/to list all available authenticated AJAX actions. - Trace Handlers: For each action, check if they call
current_user_can(). - Metadata Injection: If settings are not accessible, look for
wptravelly_save_tour_metaor similar actions that allow modifying tour prices or booking details. - Check for "No Nonce": Attempt the request without the
nonceparameter to see ifcheck_ajax_refereris also missing (this would upgrade it to a CSRF).
Summary
The WpTravelly plugin for WordPress is vulnerable to unauthorized modification of plugin settings due to missing capability checks on authenticated AJAX actions. This allows logged-in users with low privileges, such as Subscribers, to execute administrative functions like updating plugin configurations if they can obtain a valid nonce.
Vulnerable Code
// File: includes/admin/class-admin-ajax.php (inferred) add_action( 'wp_ajax_wptravelly_save_settings_data', array( $this, 'wptravelly_save_settings_data' ) ); public function wptravelly_save_settings_data() { check_ajax_referer( 'wptravelly_ajax_nonce', 'nonce' ); // Vulnerable: Missing capability check (e.g., current_user_can( 'manage_options' )) if ( isset( $_POST['settings_data'] ) ) { update_option( 'wptravelly_settings', $_POST['settings_data'] ); } wp_send_json_success(); }
Security Fix
@@ -10,6 +10,10 @@ public function wptravelly_save_settings_data() { check_ajax_referer( 'wptravelly_ajax_nonce', 'nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => 'Unauthorized access' ) ); + } + if ( isset( $_POST['settings_data'] ) ) { update_option( 'wptravelly_settings', $_POST['settings_data'] ); }
Exploit Outline
1. Authenticate to the WordPress site as a user with Subscriber-level permissions. 2. Navigate to the WordPress dashboard (/wp-admin/) and retrieve the AJAX nonce from the localized JavaScript object 'wptravelly_ajax_obj'. 3. Send a POST request to '/wp-admin/admin-ajax.php' with the 'action' parameter set to 'wptravelly_save_settings_data'. 4. Include the 'nonce' parameter and a 'settings_data' array containing the plugin options to be modified (e.g., 'tour_page_id'). 5. Verify that the plugin settings are updated despite the user lacking administrative privileges.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.