Five Star Restaurant Reservations – WordPress Booking Plugin <= 2.7.9 - Missing Authorization
Description
The Five Star Restaurant Reservations – WordPress Booking Plugin plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 2.7.9. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=2.7.9What Changed in the Fix
Changes introduced in v2.7.10
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-25327 ## 1. Vulnerability Summary The **Five Star Restaurant Reservations** plugin (<= 2.7.9) is vulnerable to **Missing Authorization** in its AJAX handlers. Specifically, several sensitive actions are registered via `wp_ajax_nopriv_` (unauthenticated) witho…
Show full research plan
Exploitation Research Plan - CVE-2026-25327
1. Vulnerability Summary
The Five Star Restaurant Reservations plugin (<= 2.7.9) is vulnerable to Missing Authorization in its AJAX handlers. Specifically, several sensitive actions are registered via wp_ajax_nopriv_ (unauthenticated) without sufficient validation that the requester is authorized to perform the action on a specific booking. While the plugin implements a nonce check and an email-matching check for functions like cancel_reservation, the reliance on a publicly available email address and a discoverable booking_id as the only authorization tokens constitutes "Missing Authorization" (or weak authorization) for unauthenticated users.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
rtb_cancel_reservations(unauthenticated) - Parameters:
action:rtb_cancel_reservationsnonce: A valid WordPress nonce for thertb-booking-formaction.booking_id: The ID (Post ID) of the target reservation.booking_email: The email address associated with the reservation.
- Authentication: None (Unauthenticated).
- Preconditions: The attacker must know the victim's email address and the specific
booking_id(which is an incrementing integer).
3. Code Flow
- Entry Point: The
Summary
The Five Star Restaurant Reservations plugin for WordPress is vulnerable to unauthorized reservation cancellation in versions up to 2.7.9. This occurs because the AJAX handlers for finding and cancelling bookings rely solely on a sequential booking ID and the customer's email address for verification. Unauthenticated attackers can exploit this to find or cancel active reservations without a unique secret or proper authorization check.
Vulnerable Code
// includes/Ajax.class.php lines 83-86 (v2.7.9) add_action( 'wp_ajax_rtb_find_reservations', array( $this, 'get_reservations' ) ); add_action( 'wp_ajax_nopriv_rtb_find_reservations', array( $this, 'get_reservations' ) ); add_action( 'wp_ajax_rtb_cancel_reservations', array( $this, 'cancel_reservation' ), 10, 0 ); add_action( 'wp_ajax_nopriv_rtb_cancel_reservations', array( $this, 'cancel_reservation' ), 10, 0 ); --- // includes/Ajax.class.php lines 161-177 (v2.7.9) public function cancel_reservation( $ajax = true ) { global $rtb_controller; if ( $ajax && !check_ajax_referer( 'rtb-booking-form', 'nonce' ) ) { rtbHelper::bad_nonce_ajax(); } $cancelled_redirect = $rtb_controller->settings->get_setting( 'cancelled-redirect-page' ); $booking_id = isset($_REQUEST['booking_id']) ? absint( $_REQUEST['booking_id'] ) : ''; $booking_email = isset($_REQUEST['booking_email']) ? sanitize_email( $_REQUEST['booking_email'] ) : ''; $success = false; $error = array( 'error' => 'unknown', 'msg' => __( 'Unkown error. Please try again', 'restaurant-reservations' ) ); $booking = new rtbBooking(); if ( $booking->load_post( $booking_id ) ) { if ( $booking_email == $booking->email ) { wp_update_post( array( 'ID' => $booking->ID, 'post_status' => 'cancelled' ) ); $success = true; }
Security Fix
@@ -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(
Exploit Outline
1. **Identify Target Data**: Obtain the Post ID (`booking_id`) of a target reservation and the associated customer email (`booking_email`). Booking IDs are sequential, making them vulnerable to enumeration. 2. **Obtain Nonce**: Access the frontend booking page and extract a valid WordPress nonce for the `rtb-booking-form` action from the JavaScript localization object or form fields. 3. **Prepare Payload**: Construct an unauthenticated AJAX request targeting `wp-admin/admin-ajax.php` with the following POST parameters: - `action`: `rtb_cancel_reservations` - `nonce`: [Extracted Nonce] - `booking_id`: [Target Post ID] - `booking_email`: [Associated Email] 4. **Trigger Cancellation**: Submit the request. The server-side logic will verify the email matches the ID in the database and, if successful, update the reservation status to 'cancelled' without requiring any secret token or user authentication.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.