[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fplgJrkIUd6WYr9CxTe8vxp0vctipPCRXXFBkjsmM688":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":28,"research_verified":29,"research_rounds_completed":30,"research_plan":31,"research_summary":32,"research_vulnerable_code":33,"research_fix_diff":34,"research_exploit_outline":35,"research_model_used":36,"research_started_at":37,"research_completed_at":38,"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":29,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":29,"source_links":39},"CVE-2026-32535","js-help-desk-ai-powered-support-ticketing-system-authenticated-subscriber-insecure-direct-object-reference","JS Help Desk – AI-Powered Support & Ticketing System \u003C= 3.0.3 - Authenticated (Subscriber+) Insecure Direct Object Reference","The JS Help Desk – AI-Powered Support & Ticketing System plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 3.0.3 due to missing validation on a user controlled key. This makes it possible for authenticated attackers, with Subscriber-level access and above, to perform unauthorized actions.","js-support-ticket",null,"\u003C=3.0.3","3.0.4","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Authorization Bypass Through User-Controlled Key","2026-03-23 00:00:00","2026-04-02 16:27:05",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F87d684ba-4856-429f-9e4e-baa61c3967e1?source=api-prod",11,[22,23,24,25,26,27],"includes\u002Factivation.php","js-support-ticket.php","modules\u002Fjssupportticket\u002Fcontroller.php","modules\u002Freply\u002Fmodel.php","modules\u002Fticket\u002Fmodel.php","readme.txt","researched",false,3,"```markdown\n# Exploitation Research Plan: CVE-2026-32535 (JS Help Desk IDOR)\n\n## 1. Vulnerability Summary\nThe **JS Help Desk – AI-Powered Support & Ticketing System** plugin (up to version 3.0.3) is vulnerable to an **Insecure Direct Object Reference (IDOR)**. The vulnerability exists in the handling of ticket-related tasks (such as closing or deleting a ticket) where the system fails to verify if the authenticated user performing the action is the owner of the object (the ticket) specified by a user-controlled identifier (`ticketid`).\n\nWhile the plugin uses a random hash for some public links to prevent unauthorized access, many internal operations rely on the raw integer ID (`ticketid`) and fail to validate ownership, allowing a Subscriber-level user to perform actions on tickets belonging to other users.\n\n## 2. Attack Vector Analysis\n- **Endpoint**: Front-end Control Panel or `admin-ajax.php`.\n- **Target Action**: `closeticket` or `deleteticket`.\n- **Vulnerable Parameter**: `ticketid` (integer).\n- **Authentication**: Authenticated (Subscriber or higher).\n- **Preconditions**:\n    - The plugin must be active.\n    - At least two users exist (Victim and Attacker).\n    - The Attacker must be able to discover or guess the Victim's `ticketid` (usually sequential integers).\n\n## 3. Code Flow\n1. The request enters via `the_","The JS Help Desk plugin for WordPress is vulnerable to Insecure Direct Object Reference (IDOR) in versions up to 3.0.3. This occurs because the plugin fails to verify if the authenticated user has ownership of the ticket specified by user-controlled parameters like 'ticket_id' or 'ticketId' in functions handling ticket replies and AI-powered support features.","\u002F\u002F modules\u002Freply\u002Fmodel.php around line 510\nfunction get_filtered_replies() {\n    \u002F\u002F Verify nonce\n    check_ajax_referer('get-filtered-replies', '_wpnonce');\n\n    $jsst_ticket_id = intval(JSSTrequest::getVar('ticket_id'));\n\n    if (!$jsst_ticket_id) {\n        wp_send_json_error(['message' => __('Ticket ID is required.', 'js-support-ticket')]);\n    }\n\n    $jsst_uids = $this->get_allowed_support_user_ids();\n    if (empty($jsst_uids)) {\n        wp_send_json_success(['replies' => [], 'count' => 0]);\n    }\n\n    $jsst_uids_str = implode(',', array_map('intval', $jsst_uids)); \u002F\u002F Ensure integers\n\n    $jsst_query = \"\n    SELECT r.*\n    FROM `\" . jssupportticket::$_db->prefix . \"js_ticket_replies` AS r\n    WHERE r.ticketid = \" . esc_sql($jsst_ticket_id) . \"\n--- \n\u002F\u002F modules\u002Fticket\u002Fmodel.php around line 3018\n$jsst_id = JSSTrequest::getVar('ticketId');\n$jsst_subject = JSSTrequest::getVar('ticketSubject');\n\n$jsst_agentquery = \"\";\n\u002F\u002F ... (missing ownership validation for regular users)\n$jsst_query = \"SELECT ticket.message\n    FROM `\" . jssupportticket::$_db->prefix . \"js_ticket_tickets` AS ticket\n    WHERE ticket.id = \" . esc_sql($jsst_id);","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fjs-support-ticket\u002F3.0.3\u002Fmodules\u002Freply\u002Fmodel.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fjs-support-ticket\u002F3.0.4\u002Fmodules\u002Freply\u002Fmodel.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fjs-support-ticket\u002F3.0.3\u002Fmodules\u002Freply\u002Fmodel.php\t2026-02-03 04:22:42.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fjs-support-ticket\u002F3.0.4\u002Fmodules\u002Freply\u002Fmodel.php\t2026-02-13 04:32:24.000000000 +0000\n@@ -510,18 +510,39 @@\n         \u002F\u002F Verify nonce\n         check_ajax_referer('get-filtered-replies', '_wpnonce');\n \n-        $jsst_ticket_id = intval(JSSTrequest::getVar('ticket_id'));\n+        \u002F\u002F Secure the ID (Stops SQL Injection)\n+        $jsst_ticket_id = JSSTrequest::getVar('ticket_id', null, 0, 'int');\n \n         if (!$jsst_ticket_id) {\n             wp_send_json_error(['message' => __('Ticket ID is required.', 'js-support-ticket')]);\n         }\n \n+        \u002F\u002F 1. Check if the user is a Agent\n+        $is_staff = (in_array('agent', jssupportticket::$_active_addons) && JSSTincluder::getJSModel('agent')->isUserStaff());\n+\n+        \u002F\u002F 2. If they are staff, check if they LACK the specific AI permission\n+        if ($is_staff) {\n+            $has_ai_permission = JSSTincluder::getJSModel('userpermissions')->checkPermissionGrantedForTask('Use AI Powered Reply Feature');\n+            if (!$has_ai_permission) { \u002F\u002F Note the \"!\" (NOT)\n+                wp_send_json_error(['message' => __('You do not have permission to use AI features.', 'js-support-ticket')]);\n+            }\n+        } \n+        \u002F\u002F 3. If they are NOT staff, check if they are an Administrator\n+        else if (!current_user_can('manage_options')) {\n+            \u002F\u002F If they aren't staff and aren't an admin, they are a normal user or guest\n+            wp_send_json_error(['message' => __('Access denied.', 'js-support-ticket')]);\n+        }\n+\n+        \u002F\u002F If it reaches here, the user is either:\n+        \u002F\u002F - Staff WITH AI permissions\n+        \u002F\u002F - An Administrator\n+\n         $jsst_uids = $this->get_allowed_support_user_ids();\n         if (empty($jsst_uids)) {\n             wp_send_json_success(['replies' => [], 'count' => 0]);\n         }\n \n-        $jsst_uids_str = implode(',', array_map('intval', $jsst_uids)); \u002F\u002F Ensure integers\n+        $jsst_uids_str = implode(',', array_map('absint', $jsst_uids)); \u002F\u002F Ensure integers\n \n         $jsst_query = \"\n         SELECT r.*\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fjs-support-ticket\u002F3.0.3\u002Fmodules\u002Fticket\u002Fmodel.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fjs-support-ticket\u002F3.0.4\u002Fmodules\u002Fticket\u002Fmodel.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fjs-support-ticket\u002F3.0.3\u002Fmodules\u002Fticket\u002Fmodel.php\t2026-02-03 04:22:42.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fjs-support-ticket\u002F3.0.4\u002Fmodules\u002Fticket\u002Fmodel.php\t2026-02-13 04:32:24.000000000 +0000\n@@ -3015,14 +3015,15 @@\n             die('Security check Failed');\n         }\n \n-        $jsst_id = JSSTrequest::getVar('ticketId');\n-        $jsst_subject = JSSTrequest::getVar('ticketSubject');\n+        \u002F\u002F Explicitly cast to integer to kill SQL Injection payloads\n+        $jsst_id = absint(JSSTrequest::getVar('ticketId')); \n+        $jsst_subject = sanitize_text_field(JSSTrequest::getVar('ticketSubject'));\n \n         $jsst_agentquery = \"\";\n         if (in_array('agent', jssupportticket::$_active_addons) && JSSTincluder::getJSModel('agent')->isUserStaff()) {\n             $jsst_allowed = JSSTincluder::getJSModel('userpermissions')->checkPermissionGrantedForTask('Limit AI Replies to Agent-Assigned Tickets');\n             if ($jsst_allowed) {\n-                $jsst_staffid = JSSTincluder::getJSModel('agent')->getStaffId(JSSTincluder::getObjectClass('user')->uid());\n+                $jsst_staffid = absint(JSSTincluder::getJSModel('agent')->getStaffId(JSSTincluder::getObjectClass('user')->uid()));\n                 $jsst_agentquery = \" AND (t.staffid = \" . esc_sql($jsst_staffid) . \" OR t.departmentid IN (\n                     SELECT dept.departmentid\n                     FROM `\" . jssupportticket::$_db->prefix . \"js_ticket_acl_user_access_departments` AS dept\n@@ -3038,6 +3039,9 @@\n             FROM `\" . jssupportticket::$_db->prefix . \"js_ticket_tickets` AS ticket\n             WHERE ticket.id = \" . esc_sql($jsst_id);\n         $jsst_ticket_data = jssupportticket::$_db->get_row($jsst_query);\n+\n+        if (!$jsst_ticket_data) return json_encode([]);\n+\n         $jsst_message = wp_strip_all_tags($jsst_ticket_data->message);","The exploit targets AJAX endpoints or internal plugin controllers that handle ticket operations. \n\n1.  **Authentication**: The attacker logs in as a Subscriber-level user.\n2.  **Discovery**: The attacker identifies the `ticket_id` (integer) of a victim's ticket. These are often sequential and easy to guess.\n3.  **Request**: The attacker sends a request to an endpoint like `wp-admin\u002Fadmin-ajax.php` with the `action` parameter set to a vulnerable task (e.g., `get-filtered-replies`). \n4.  **Payload**: The payload includes the victim's `ticket_id` and a valid security nonce (which is often available in the HTML of the user's own control panel). \n5.  **Bypass**: Because the vulnerable version only checks for a valid integer ID and a general nonce, but fails to check if the `uid` of the ticket matches the `uid` of the current requester, the system executes the action (e.g., returning sensitive ticket replies or modifying ticket status) regardless of ownership.","gemini-3-flash-preview","2026-04-18 00:12:23","2026-04-18 00:13:23",{"type":40,"vulnerable_version":41,"fixed_version":11,"vulnerable_browse":42,"vulnerable_zip":43,"fixed_browse":44,"fixed_zip":45,"all_tags":46},"plugin","3.0.3","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fjs-support-ticket\u002Ftags\u002F3.0.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fjs-support-ticket.3.0.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fjs-support-ticket\u002Ftags\u002F3.0.4","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fjs-support-ticket.3.0.4.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fjs-support-ticket\u002Ftags"]