GeekyBot — AI Copilot, Chatbot, WooCommerce Lead Gen & Zero-Prompt Content <= 1.2.2 - Unauthenticated Arbitrary File Upload
Description
The GeekyBot — AI Copilot, Chatbot, WooCommerce Lead Gen & Zero-Prompt Content plugin for WordPress is vulnerable to arbitrary file uploads due to missing file type validation in all versions up to, and including, 1.2.2. This makes it possible for unauthenticated attackers to upload arbitrary files on the affected site's server which may make remote code execution possible.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:HTechnical Details
What Changed in the Fix
Changes introduced in v1.2.3
Source Code
WordPress.org SVN# Research Plan: CVE-2026-40772 - GeekyBot Arbitrary File Upload ## Vulnerability Summary The **GeekyBot — AI Copilot, Chatbot, WooCommerce Lead Gen & Zero-Prompt Content** plugin (<= 1.2.2) is vulnerable to an unauthenticated arbitrary file upload. The vulnerability exists because the plugin's fil…
Show full research plan
Research Plan: CVE-2026-40772 - GeekyBot Arbitrary File Upload
Vulnerability Summary
The GeekyBot — AI Copilot, Chatbot, WooCommerce Lead Gen & Zero-Prompt Content plugin (<= 1.2.2) is vulnerable to an unauthenticated arbitrary file upload. The vulnerability exists because the plugin's file upload handling logic (likely in the lead generation or chatbot attachment modules) lacks sufficient file type validation. This allows unauthenticated users to upload executable files (e.g., .php) to the server, leading to Remote Code Execution (RCE).
The vulnerability is reachable through the plugin's custom request handler in modules/geekybot/controller.php, which manages layout inclusions and module logic based on user-supplied parameters.
Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php(via the plugin's custom AJAX/request dispatcher) or the root site/with specific parameters. - Action/Hook: The plugin uses an
inithook (viaGEEKYBOTgeekybotControllerinstantiation) and custom AJAX filters. - Vulnerable Parameter:
$_FILES['...'](likely namedfile,attachment, orbot_custom_img). - Authentication: None required (Unauthenticated).
- Preconditions: A valid
geekybot_noncemust be obtained, which is exposed to unauthenticated users on any page where the chatbot is active.
Summary
The GeekyBot plugin for WordPress is vulnerable to unauthenticated arbitrary file uploads due to missing file type validation and a dynamic method call vulnerability in its product loading logic. Attackers can exploit an effectively disabled nonce check to invoke arbitrary model methods, which can be leveraged to upload executable PHP files to the server.
Vulnerable Code
/* modules/geekybot/model.php:466 */ function geekybotLoadMoreProducts(){ $nonce = GEEKYBOTrequest::GEEKYBOT_getVar('_wpnonce'); if (! wp_verify_nonce( $nonce, 'load-more') ) { // disable nonce // die( 'Security check Failed' ); } $msg = GEEKYBOTrequest::GEEKYBOT_getVar('msg'); $data = GEEKYBOTrequest::GEEKYBOT_getVar('data'); $next_page = GEEKYBOTrequest::GEEKYBOT_getVar('next_page'); $functionName = GEEKYBOTrequest::GEEKYBOT_getVar('functionName'); $modelName = GEEKYBOTrequest::GEEKYBOT_getVar('modelName'); if(!is_array($data)) { $data = json_decode($data,true); } $products = GEEKYBOTincluder::GEEKYBOT_getModel($modelName)->$functionName($msg, $data, $next_page); // save bot response to the session and chat history geekybot::$_geekybotsessiondata->geekybot_addChatHistoryToSession($products, 'bot'); GEEKYBOTincluder::GEEKYBOT_getModel('chathistory')->SaveChathistoryFromchatServer($products, 'bot'); return $products; }
Security Fix
@@ -463,25 +463,74 @@ return $imgPath; } - function geekybotLoadMoreProducts(){ + function geekybotLoadMoreProducts() { + // 1. STOPS execution if the nonce is invalid $nonce = GEEKYBOTrequest::GEEKYBOT_getVar('_wpnonce'); - if (! wp_verify_nonce( $nonce, 'load-more') ) { - // disable nonce - // die( 'Security check Failed' ); + if (!wp_verify_nonce($nonce, 'load-more')) { + wp_send_json_error('Security check Failed', 403); + exit; } + $msg = GEEKYBOTrequest::GEEKYBOT_getVar('msg'); $data = GEEKYBOTrequest::GEEKYBOT_getVar('data'); $next_page = GEEKYBOTrequest::GEEKYBOT_getVar('next_page'); - $functionName = GEEKYBOTrequest::GEEKYBOT_getVar('functionName'); $modelName = GEEKYBOTrequest::GEEKYBOT_getVar('modelName'); - if(!is_array($data)) { - $data = json_decode($data,true); + $functionName = GEEKYBOTrequest::GEEKYBOT_getVar('functionName'); + + // 2. THE ALLOWLIST MAP + // This defines exactly which models and functions are publically accessible. + $allowed_map = [ + 'woocommerce' => [ + 'geekybot_showAllProducts', + 'geekybot_searchProduct', + 'geekybot_getProductsUnderPrice', + 'geekybot_getProductsAbovePrice', + 'geekybot_getProductsBetweenPrice', + 'showProductsList' + ], + 'woocommercepropack' => [ + 'geekybot_showAllSaleProducts', + 'geekybot_showAllTrendingProducts', + 'geekybot_showAllLatestProducts', + 'geekybot_showAllHighestRatedProducts', + 'geekybot_viewOrders' + ] + ]; + + // 3. VALIDATION LOGIC + // Check if the model exists in our map + if (!isset($allowed_map[$modelName])) { + wp_send_json_error('Unauthorized Model', 403); + exit; } - $products = GEEKYBOTincluder::GEEKYBOT_getModel($modelName)->$functionName($msg, $data, $next_page); - // save bot response to the session and chat history - geekybot::$_geekybotsessiondata->geekybot_addChatHistoryToSession($products, 'bot'); - GEEKYBOTincluder::GEEKYBOT_getModel('chathistory')->SaveChathistoryFromchatServer($products, 'bot'); - return $products; + + // Check if the function is allowed for that specific model + if (!in_array($functionName, $allowed_map[$modelName])) { + wp_send_json_error('Unauthorized Function', 403); + exit; + } + + // 4. SAFE EXECUTION + $model = GEEKYBOTincluder::GEEKYBOT_getModel($modelName); + + // Final check to ensure the method actually exists in the class + if ($model && method_exists($model, $functionName)) { + + if(!is_array($data)) { + $data = json_decode($data, true); + } + + $products = $model->$functionName($msg, $data, $next_page); + + // save bot response + geekybot::$_geekybotsessiondata->geekybot_addChatHistoryToSession($products, 'bot'); + GEEKYBOTincluder::GEEKYBOT_getModel('chathistory')->SaveChathistoryFromchatServer($products, 'bot'); + + return $products; + } + + wp_send_json_error('Execution failed', 500); + exit; }
Exploit Outline
To exploit this vulnerability, an unauthenticated attacker first obtains a valid 'load-more' nonce, which is typically exposed in the client-side scripts of the chatbot. The attacker then sends a POST request to the plugin's AJAX handler (invoking geekybotLoadMoreProducts) with the 'modelName' and 'functionName' parameters set to target an internal method that handles file processing or image saving. Because the nonce check in version 1.2.2 does not terminate execution on failure and the plugin lacks an allowlist for these dynamic method calls, the attacker can trigger file upload routines with a malicious PHP payload in the $_FILES array, resulting in the creation of a webshell on the server.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.