Awesome Support <= 6.3.7 - Authenticated (Subscriber+) Insecure Direct Object Reference to Unauthorized Ticket Reply Access via 'ticket_id' Parameter
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:NTechnical Details
<=6.3.7What Changed in the Fix
Changes introduced in v6.3.8
Source Code
WordPress.org SVN# 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 inassets/admin/js/admin-print-ticket.js) orwpas_get_ticket_replies_ajax(as per the CVE description). - HTTP Method:
POST - Vulnerable Parameter:
id(orticket_id) - Authentication Required: Authenticated (
Subscriberrole or higher). - Preconditions: The attacker must obtain a valid WordPress AJAX nonce, typically localized as
WPAS_Print.nonce.
3. Code Flow
- Entry Point: An authenticated user sends a
POSTrequest toadmin-ajax.phpwith the actionwpas_get_ticket_for_print. - Nonce Verification: The handler calls
check_ajax_referer()orwp_verify_nonce()using the providednonceparameter and the action string (likely'wpas-print-ticket'). - Missing Authorization Sink: The backend function (likely in an admin controller) retrieves the ticket object using
get_post( $id ). - Information Disclosure: The code proceeds to fetch all related posts with types
ticket_reply,ticket_note, andticket_historywithout checking if thepost_authorof the ticket matches the current user ID or if the user hasedit_others_ticketscapabilities. - 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.
- Identify Script Localization: The script
assets/admin/js/admin-print-ticket.jsis enqueued with the localization objectWPAS_Print. - Navigation: Use
browser_navigateto go to the ticket list or the main dashboard:/wp-admin/edit.php?post_type=ticket. - Extraction:
// Use browser_eval to extract the nonce const nonce = window.WPAS_Print?.nonce; return nonce; - Alternative: If the Subscriber is barred from the backend, check if
WPAS_Printis 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
- Admin User: Create a "Sensitive Ticket" (Post Type:
ticket).- Title: "Server Migration Credentials"
- Content: "The root password is 'P4ssw0rd!'"
- Private Note: Add a private note to this ticket (Post Type:
ticket_note).- Content: "Also, the database secret is 'db_admin_123'"
- Subscriber User: Create a user
attacker_subwith theSubscriberrole. - Attacker Ticket: (Optional) Create one ticket for
attacker_subto ensure they have access to the "My Tickets" page where the nonce is likely localized.
7. Expected Results
- The server returns an
HTTP 200 OKresponse. - The response body contains an HTML string (the rendered
print-ticket.phpview). - The HTML content reveals the "Sensitive Ticket" title, the root password from the content, and the database secret from the
ticket_notesection, which should have been hidden from the Subscriber.
8. Verification Steps
- Response Inspection: Search the AJAX response for the string
"Private note". - Data Comparison: Verify the disclosed password in the response matches the one created in the Test Data Setup.
- 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_canorpost_authorcheck, 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).
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
@@ -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.