CVE-2025-14034

ilGhera Support System for WooCommerce <= 1.2.6 - Missing Authorization to Authenticated (Subscriber+) Arbitrary Ticket Deletion

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
1.2.7
Patched in
1d
Time to patch

Description

The ilGhera Support System for WooCommerce plugin for WordPress is vulnerable to unauthorized modification and loss of data due to a missing capability check on the 'delete_single_ticket_callback' and 'change_ticket_status_callback' functions in all versions up to, and including, 1.2.6. This makes it possible for authenticated attackers, with Subscriber-level access and above, to delete arbitrary support tickets and modify their status.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.2.6
PublishedJanuary 5, 2026
Last updatedJanuary 6, 2026
Affected pluginwc-support-system

What Changed in the Fix

Changes introduced in v1.2.7

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Vulnerability Research Plan: CVE-2025-14034 (ilGhera Support System for WooCommerce) ## 1. Vulnerability Summary The **ilGhera Support System for WooCommerce** plugin (versions <= 1.2.6) contains a missing authorization vulnerability in its AJAX handlers for ticket management. Specifically, the f…

Show full research plan

Vulnerability Research Plan: CVE-2025-14034 (ilGhera Support System for WooCommerce)

1. Vulnerability Summary

The ilGhera Support System for WooCommerce plugin (versions <= 1.2.6) contains a missing authorization vulnerability in its AJAX handlers for ticket management. Specifically, the functions delete_single_ticket_callback and change_ticket_status_callback are registered via the wp_ajax_ hook but fail to implement capability checks (e.g., current_user_can()) or ownership validation. This allows any authenticated user (starting from the Subscriber role) to delete or modify the status of arbitrary support tickets by sending a crafted AJAX request with a valid nonce.

2. Attack Vector Analysis

  • Endpoints: /wp-admin/admin-ajax.php
  • AJAX Actions:
    • delete-ticket (for arbitrary ticket deletion)
    • change-ticket-status (for arbitrary status modification)
  • Vulnerable Functions: delete_single_ticket_callback and change_ticket_status_callback in includes/class-wc-support-system.php.
  • Authentication: Authenticated (Subscriber-level or higher).
  • Preconditions:
    • The plugin must be active.
    • WooCommerce must be installed and active.
    • A valid nonce for the specific action must be obtained.
    • The attacker must know (or brute-force) the ticket_id.

3. Code Flow

  1. Registration: In includes/class-wc-support-system.php, the __construct method (lines 69-71) registers the AJAX handlers:
    add_action( 'wp_ajax_delete-ticket', array( $this, 'delete_single_ticket_callback' ) );
    add_action( 'wp_ajax_change-ticket-status', array( $this, 'change_ticket_status_callback' ) );
    
  2. Execution: When a logged-in user sends a request to admin-ajax.php with action=delete-ticket, WordPress executes delete_single_ticket_callback.
  3. Missing Check: The callback functions verify the nonce (see section 4) but lack a current_user_can('manage_options') check or logic to ensure the ticket_id belongs to the requesting user.
  4. Sink: The functions perform direct database deletions or updates on the support ticket tables based on the provided ticket_id parameter.

4. Nonce Acquisition Strategy

The plugin exposes the necessary nonces to authenticated users via wp_localize_script in the wss_scripts (front-end) and wss_admin_scripts (back-end) functions.

Steps to obtain nonces:

  1. Identify the Support Page: The plugin enqueues its scripts on the page defined in the WordPress option wss-page.
  2. Setup: Ensure a page contains the shortcode [support-tickets-table].
  3. Observation: The scripts are localized under the global JavaScript object wssData.
  4. Acquisition:
    • Log in as a Subscriber.
    • Navigate to the support page.
    • Use browser_eval to extract the nonces:
      • deleteSingleTicketNonce: wssData.deleteSingleTicketNonce
      • changeTicketStatusNonce: wssData.changeTicketStatusNonce

Action Strings (from lines 112-113):

  • wss-delete-single-ticket
  • wss-change-ticket-status

5. Exploitation Strategy

Arbitrary Ticket Deletion

  • Method: POST
  • URL: http://<target>/wp-admin/admin-ajax.php
  • Body (URL-encoded):
    • action: delete-ticket
    • ticket_id: [ID_OF_TARGET_TICKET]
    • security: [deleteSingleTicketNonce]
  • Expected Response: 1 (or JSON success message, depending on internal callback implementation).

Arbitrary Ticket Status Change

  • Method: POST
  • URL: http://<target>/wp-admin/admin-ajax.php
  • Body (URL-encoded):
    • action: change-ticket-status
    • ticket_id: [ID_OF_TARGET_TICKET]
    • status: closed (or other valid status)
    • security: [changeTicketStatusNonce]

6. Test Data Setup

  1. Prerequisite: Install and activate WooCommerce.
  2. Plugin Setup: Activate ilGhera Support System for WooCommerce.
  3. Configuration:
    • Create a page titled "Support" with content [support-tickets-table].
    • Set the plugin option wss-page to the ID of this new page (wp option update wss-page <page_id>).
  4. User Creation:
    • Create an Admin user (to create "victim" data).
    • Create a Subscriber user (the attacker).
  5. Data Creation:
    • As Admin, create a support ticket.
    • Use wp db query to find the ID of the created ticket in the custom table (typically wp_wss_tickets).

7. Expected Results

  • Deletion: The ticket record with the specified ticket_id should be removed from the database.
  • Status Change: The status column for the specified ticket_id should be updated to the attacker-supplied value.
  • Unauthorized Access: Both actions should succeed even when performed by a Subscriber who does not own the ticket and has no administrative privileges.

8. Verification Steps

After performing the HTTP requests:

  1. Verify Deletion:
    wp db query "SELECT * FROM wp_wss_tickets WHERE id = [ID_OF_TARGET_TICKET]"
    # Expected: Empty result
    
  2. Verify Status Change:
    wp db query "SELECT status FROM wp_wss_tickets WHERE id = [ID_OF_TARGET_TICKET]"
    # Expected: The status matches the value sent in the exploit
    

9. Alternative Approaches

If the ticket_id is not passed as ticket_id, try id. If the nonce parameter is not security, try nonce or wss_nonce, as these are common patterns in ilGhera plugins. Check the js/wss.js file via http_request if parameter names need confirmation.

Research Findings
Static analysis — not yet PoC-verified

Summary

The ilGhera Support System for WooCommerce plugin for WordPress is vulnerable to unauthorized data modification and loss due to missing capability and ownership checks in its AJAX handlers. This allow authenticated users, such as Subscribers, to delete arbitrary support tickets or modify their status by providing a valid nonce and ticket ID.

Vulnerable Code

// includes/class-wc-support-system.php around line 870
public function change_ticket_status_callback() {

	$ticket_id  = isset( $_POST['ticket_id'] ) ? sanitize_text_field( wp_unslash( $_POST['ticket_id'] ) ) : '';
	$new_status = isset( $_POST['status'] ) ? sanitize_text_field( wp_unslash( $_POST['status'] ) ) : '';
	$update_time = current_time( 'mysql' );

	if ( $ticket_id && $new_status ) {

		$this->update_ticket( $ticket_id, $update_time, $new_status );

---

// includes/class-wc-support-system.php around line 1332
public function delete_single_ticket_callback() {

	if ( isset( $_POST['wss-delete-single-ticket-nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['wss-delete-single-ticket-nonce'] ) ), 'wss-delete-single-ticket' ) ) {

		$ticket_id = isset( $_POST['ticket_id'] ) ? sanitize_text_field( wp_unslash( $_POST['ticket_id'] ) ) : '';

		if ( $ticket_id ) {

			$this->delete_ticket( $ticket_id );

Security Fix

Only in /home/deploy/wp-safety.org/data/plugin-versions/wc-support-system/1.2.6: composer.json
Only in /home/deploy/wp-safety.org/data/plugin-versions/wc-support-system/1.2.6: composer.lock
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/wc-support-system/1.2.6/includes/class-wc-support-system.php /home/deploy/wp-safety.org/data/plugin-versions/wc-support-system/1.2.7/includes/class-wc-support-system.php
--- /home/deploy/wp-safety.org/data/plugin-versions/wc-support-system/1.2.6/includes/class-wc-support-system.php	2025-10-06 09:24:52.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wc-support-system/1.2.7/includes/class-wc-support-system.php	2025-12-23 11:44:20.000000000 +0000
@@ -872,6 +872,18 @@
 
 			if ( $ticket_id && $new_status ) {
 
+				// Check user capabilities
+				$has_admin_capability = current_user_can( 'manage_woocommerce' ) || current_user_can( 'manage_options' );
+
+				if ( ! $has_admin_capability ) {
+					// If not admin/shop manager, check if user owns the ticket
+					$ticket = self::get_ticket( $ticket_id );
+					if ( ! $ticket || (int) $ticket->user_id !== get_current_user_id() ) {
+						wp_send_json_error( array( 'message' => __( 'You do not have permission to change this ticket status.', 'wc-support-system' ) ) );
+						exit;
+					}
+				}
+
 				$this->update_ticket( $ticket_id, $update_time, $new_status );
 				$new_label = self::get_ticket_status_label( $new_status );
 
@@ -1263,6 +1275,12 @@
 
 		if ( isset( $_POST['wss-delete-single-thread-nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['wss-delete-single-thread-nonce'] ) ), 'wss-delete-single-thread' ) ) {
 
+			// Check user capabilities - only shop managers and administrators can delete threads
+			if ( ! current_user_can( 'manage_woocommerce' ) && ! current_user_can( 'manage_options' ) ) {
+				wp_send_json_error( array( 'message' => __( 'You do not have permission to delete threads.', 'wc-support-system' ) ) );
+				exit;
+			}
+
 			$thread_id = isset( $_POST['thread_id'] ) ? sanitize_text_field( wp_unslash( $_POST['thread_id'] ) ) : $thread_id;
 
 			if ( $thread_id ) {
@@ -1332,6 +1350,12 @@
 
 		if ( isset( $_POST['wss-delete-single-ticket-nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['wss-delete-single-ticket-nonce'] ) ), 'wss-delete-single-ticket' ) ) {
 
+			// Check user capabilities - only shop managers and administrators can delete tickets
+			if ( ! current_user_can( 'manage_woocommerce' ) && ! current_user_can( 'manage_options' ) ) {
+				wp_send_json_error( array( 'message' => __( 'You do not have permission to delete tickets.', 'wc-support-system' ) ) );
+				exit;
+			}
+
 			$ticket_id = isset( $_POST['ticket_id'] ) ? sanitize_text_field( wp_unslash( $_POST['ticket_id'] ) ) : '';
 
 			if ( $ticket_id ) {

Exploit Outline

The exploit target the WordPress AJAX endpoint (/wp-admin/admin-ajax.php) using an authenticated session (Subscriber role or higher). 1. The attacker logs in and visits a page where the plugin's scripts are enqueued (such as the support ticket dashboard). 2. The attacker extracts the required nonces for ticket deletion or status modification from the global 'wssData' JavaScript object localized in the page source. 3. To delete a ticket, the attacker sends a POST request with the 'action' parameter set to 'delete-ticket', the target 'ticket_id', and the 'wss-delete-single-ticket-nonce'. 4. To modify a ticket status, the attacker sends a POST request with the 'action' set to 'change-ticket-status', the target 'ticket_id', the desired 'status' string, and the 'changeTicketStatusNonce' (passed as the 'security' or 'wss-change-ticket-status' parameter depending on implementation details). 5. Because the vulnerable versions lack capability checks, the plugin processes the request for any valid ID regardless of who owns the ticket or whether the user is an administrator.

Check if your site is affected.

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