CVE-2026-4654

Awesome Support <= 6.3.7 - Authenticated (Subscriber+) Insecure Direct Object Reference to Unauthorized Ticket Reply Access via 'ticket_id' Parameter

mediumAuthorization Bypass Through User-Controlled Key
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
6.3.8
Patched in
1d
Time to patch

Description

The Awesome Support – WordPress HelpDesk & Support Plugin plugin for WordPress is vulnerable to Insecure Direct Object Reference in versions up to, and including, 6.3.7. This is due to the wpas_get_ticket_replies_ajax() function failing to verify whether the authenticated user has permission to view the specific ticket being requested. This makes it possible for authenticated attackers, with subscriber-level access and above, to access sensitive information from all support tickets in the system by manipulating the ticket_id parameter.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=6.3.7
PublishedApril 7, 2026
Last updatedApril 8, 2026
Affected pluginawesome-support

What Changed in the Fix

Changes introduced in v6.3.8

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-4654 - Awesome Support IDOR ## 1. Vulnerability Summary The **Awesome Support** plugin (<= 6.3.7) is vulnerable to an **Insecure Direct Object Reference (IDOR)**. The vulnerability exists in the AJAX handler responsible for fetching ticket replies (identified …

Show full research plan

Exploitation Research Plan: CVE-2026-4654 - Awesome Support IDOR

1. Vulnerability Summary

The Awesome Support plugin (<= 6.3.7) is vulnerable to an Insecure Direct Object Reference (IDOR). The vulnerability exists in the AJAX handler responsible for fetching ticket replies (identified in the description as wpas_get_ticket_replies_ajax() and appearing in source as part of the wpas_get_ticket_for_print action).

The application fails to verify if the currently authenticated user (even with a low-privilege Subscriber role) has the authorization to view the ticket identified by the ticket_id (or id) parameter. Consequently, any logged-in user can access the contents and private replies/notes of any support ticket in the database by simply guessing or incrementing the ID.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: wpas_get_ticket_for_print (as seen in assets/admin/js/admin-print-ticket.js) or wpas_get_ticket_replies_ajax (as per the CVE description).
  • HTTP Method: POST
  • Vulnerable Parameter: id (or ticket_id)
  • Authentication Required: Authenticated (Subscriber role or higher).
  • Preconditions: The attacker must obtain a valid WordPress AJAX nonce, typically localized as WPAS_Print.nonce.

3. Code Flow

  1. Entry Point: An authenticated user sends a POST request to admin-ajax.php with the action wpas_get_ticket_for_print.
  2. Nonce Verification: The handler calls check_ajax_referer() or wp_verify_nonce() using the provided nonce parameter and the action string (likely 'wpas-print-ticket').
  3. Missing Authorization Sink: The backend function (likely in an admin controller) retrieves the ticket object using get_post( $id ).
  4. Information Disclosure: The code proceeds to fetch all related posts with types ticket_reply, ticket_note, and ticket_history without checking if the post_author of the ticket matches the current user ID or if the user has edit_others_tickets capabilities.
  5. Output: The content is rendered using the template includes/admin/views/print-ticket.php, which explicitly includes private notes:
    // From includes/admin/views/print-ticket.php
    <table class="<?php echo ( $reply->post_type == 'ticket_note' ) ? 'wpas-print-ticket-notes' : 'wpas-print-ticket-reply'; ?>">
    ...
    <?php if ( $reply->post_type == 'ticket_note' ) printf( ' - <strong>%s</strong>', esc_html__( 'Private note', 'awesome-support' ) ); ?>
    

4. Nonce Acquisition Strategy

The nonce is localized in the WordPress admin dashboard for users who have access to ticket-related pages. Even a Subscriber may have access to the backend if Awesome Support is configured to use the admin area for the "My Tickets" view.

  1. Identify Script Localization: The script assets/admin/js/admin-print-ticket.js is enqueued with the localization object WPAS_Print.
  2. Navigation: Use browser_navigate to go to the ticket list or the main dashboard: /wp-admin/edit.php?post_type=ticket.
  3. Extraction:
    // Use browser_eval to extract the nonce
    const nonce = window.WPAS_Print?.nonce;
    return nonce;
    
  4. Alternative: If the Subscriber is barred from the backend, check if WPAS_Print is localized on the frontend "My Tickets" page (shortcode [tickets]).

5. Exploitation Strategy

Step 1: Discover Target ID

Identify a sensitive ticket ID (e.g., Ticket #1, created by an Admin containing credentials).

Step 2: Perform IDOR Request

Send a crafted request to the AJAX endpoint to retrieve the full content of the target ticket, including private notes.

Request Template:

  • URL: http://<target>/wp-admin/admin-ajax.php
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Body:
    action=wpas_get_ticket_for_print&id=<TARGET_TICKET_ID>&nonce=<STOLEN_NONCE>
    

6. Test Data Setup

  1. Admin User: Create a "Sensitive Ticket" (Post Type: ticket).
    • Title: "Server Migration Credentials"
    • Content: "The root password is 'P4ssw0rd!'"
  2. Private Note: Add a private note to this ticket (Post Type: ticket_note).
    • Content: "Also, the database secret is 'db_admin_123'"
  3. Subscriber User: Create a user attacker_sub with the Subscriber role.
  4. Attacker Ticket: (Optional) Create one ticket for attacker_sub to ensure they have access to the "My Tickets" page where the nonce is likely localized.

7. Expected Results

  • The server returns an HTTP 200 OK response.
  • The response body contains an HTML string (the rendered print-ticket.php view).
  • The HTML content reveals the "Sensitive Ticket" title, the root password from the content, and the database secret from the ticket_note section, which should have been hidden from the Subscriber.

8. Verification Steps

  1. Response Inspection: Search the AJAX response for the string "Private note".
  2. Data Comparison: Verify the disclosed password in the response matches the one created in the Test Data Setup.
  3. CLI Confirmation:
    # Confirm the ticket author is NOT the Subscriber
    wp post get <TARGET_ID> --field=post_author
    # Compare with Subscriber ID
    wp user get attacker_sub --field=ID
    

9. Alternative Approaches

If wpas_get_ticket_for_print is strictly protected by a capability check, test the alternative action mentioned in the CVE description:

  • Action: wpas_get_ticket_replies_ajax
  • Parameter: ticket_id
  • Expected Behavior: This endpoint likely returns a JSON blob of replies. If it lacks the current_user_can or post_author check, it will leak the same sensitive info.

If the nonce is missing, check if wpas_get_ticket_replies_ajax was registered using wp_ajax_nopriv_ (unlikely for a Subscriber+ vuln, but worth checking).

Research Findings
Static analysis — not yet PoC-verified

Summary

The Awesome Support plugin for WordPress is vulnerable to an Insecure Direct Object Reference (IDOR) in versions up to 6.3.7. The AJAX function `wpas_get_ticket_replies_ajax` fails to verify if the requester is authorized to view the specific ticket identified by the `ticket_id` parameter, allowing low-privileged authenticated users (Subscriber+) to access sensitive ticket data, including private notes.

Vulnerable Code

// includes/functions-post.php line 1822
	$ticket_id = absint( $_POST['ticket_id'] );	

	//Check permission for capability of current user
	if ( ! current_user_can( 'reply_ticket' ) ) {
		wp_send_json_error( array('message' => __('Unauthorized action. You do not have permission to load TinyMCE via Ajax request to edit a reply.', 'awesome-support') ), 403);		
    }	
		
	if( !check_ajax_referer( 'wpas_loads_replies', 'ticket_replies_nonce', false ) ) {		
		wp_send_json_error( array( 'message' => "You don't have access to perform this action" ) );
		die();
	}

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/awesome-support/6.3.7/includes/functions-post.php	2025-09-22 18:48:12.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/awesome-support/6.3.8/includes/functions-post.php	2026-04-02 16:18:42.000000000 +0000
@@ -1822,14 +1822,27 @@
 	
 	$ticket_id = absint( $_POST['ticket_id'] );	
 
-	//Check permission for capability of current user
-	if ( ! current_user_can( 'reply_ticket' ) ) {
-		wp_send_json_error( array('message' => __('Unauthorized action. You do not have permission to load TinyMCE via Ajax request to edit a reply.', 'awesome-support') ), 403);		
-    }	
-		
-	if( !check_ajax_referer( 'wpas_loads_replies', 'ticket_replies_nonce', false ) ) {		
-		wp_send_json_error( array( 'message' => "You don't have access to perform this action" ) );
-		die();
+	/* Check if the ticket is public (wpas_pbtk_flag) - only allow public access if the Public Tickets add-on is active */
+	$pbtk_flag = get_post_meta( $ticket_id , '_wpas_pbtk_flag', true );		
+	if ( class_exists( 'AS_Publictickets_Loader' ) && 'public' === $pbtk_flag ) {
+		$can_view = true;
+	}
+	else
+	{
+		//Check permission for VIEW capability of current user
+		if ( ! wpas_can_view_ticket( $ticket_id ) ) {
+			wp_send_json_error( array('message' => esc_html__('You are not allowed to view this ticket.', 'awesome-support') ), 403);
+			die();
+		}
+		//Check permission for REPLY capability of current user
+		if ( ! current_user_can( 'reply_ticket' ) ) {
+			wp_send_json_error( array('message' => esc_html__('Unauthorized action. You do not have permission to load TinyMCE via Ajax request to edit a reply.', 'awesome-support') ), 403);		
+	    }	
+		//Check permission for Valid nonce of current user
+		if( !check_ajax_referer( 'wpas_loads_replies', 'ticket_replies_nonce', false ) ) {		
+			wp_send_json_error( array( 'message' =>  esc_html__("You don't have access to perform this action", 'awesome-support') ), 403 );
+			die();
+		}
 	}

Exploit Outline

1. Authenticate as a user with at least Subscriber privileges. 2. Locate a valid AJAX nonce for the 'wpas_loads_replies' action (typically found localized in the admin dashboard scripts, for instance under the 'WPAS_Print' or similar global JS objects). 3. Identify the numeric ID of a target support ticket belonging to another user. 4. Send a POST request to `/wp-admin/admin-ajax.php` with the following parameters: `action=wpas_get_ticket_replies_ajax`, `ticket_id=<TARGET_ID>`, and `ticket_replies_nonce=<VALID_NONCE>`. 5. The server will respond with a JSON array containing the full reply history and private notes of the target ticket, bypassing intended ownership restrictions.

Check if your site is affected.

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