CVE-2025-14581

HAPPY – Helpdesk Support Ticket System <= 1.0.9 - Missing Authorization to Authenticated (Subscriber+) Arbitrary Ticket Reply

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.0.10
Patched in
105d
Time to patch

Description

The HAPPY – Helpdesk Support Ticket System plugin for WordPress is vulnerable to authorization bypass due to a missing capability check on the 'submit_form_reply' AJAX action in all versions up to, and including, 1.0.9. This makes it possible for authenticated attackers, with Subscriber-level access and above, to submit replies to arbitrary support tickets by manipulating the 'happy_topic_id' parameter, regardless of whether they are the ticket owner or have been assigned to the ticket.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.0.9
PublishedDecember 12, 2025
Last updatedMarch 27, 2026

Source Code

WordPress.org SVN
Patched

Patched version not available.

Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-14581 (HAPPY Helpdesk Ticket System) ## 1. Vulnerability Summary The **HAPPY – Helpdesk Support Ticket System** plugin (<= 1.0.9) contains a missing authorization vulnerability in its AJAX reply handling logic. The `submit_form_reply` action allows any authent…

Show full research plan

Exploitation Research Plan: CVE-2025-14581 (HAPPY Helpdesk Ticket System)

1. Vulnerability Summary

The HAPPY – Helpdesk Support Ticket System plugin (<= 1.0.9) contains a missing authorization vulnerability in its AJAX reply handling logic. The submit_form_reply action allows any authenticated user (Subscriber level or higher) to post a reply to any ticket ID. The plugin fails to verify if the requesting user is either the original author of the ticket or an assigned support agent before processing the reply submission.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: submit_form_reply
  • Vulnerable Parameter: happy_topic_id (The ID of the ticket to receive the reply).
  • Authentication: Required (Subscriber+).
  • Preconditions: At least one support ticket must exist in the system that the attacker does not own.

3. Code Flow (Inferred)

  1. Hook Registration: The plugin registers the AJAX action:
    add_action('wp_ajax_submit_form_reply', array($this, 'submit_form_reply'));
  2. Handler Entry: The submit_form_reply() function is called.
  3. Nonce Verification: The function likely calls check_ajax_referer() or wp_verify_nonce() using a nonce passed via $_POST['security'] or $_POST['_wpnonce'].
  4. Input Extraction: The function retrieves happy_topic_id and the reply content (e.g., reply_msg) from the $_POST array.
  5. Vulnerable Point: The code proceeds to save the reply (likely via wp_insert_comment or a custom table entry) using the provided happy_topic_id. It missing a call like:
    $ticket = get_post($topic_id);
    if ($ticket->post_author != get_current_user_id() && !current_user_can('manage_options')) { 
        wp_die('Unauthorized'); 
    }
    
  6. Execution: The reply is successfully linked to the target happy_topic_id.

4. Nonce Acquisition Strategy

The plugin likely enqueues a script on the frontend ticket dashboard or individual ticket pages. We need to extract the nonce used for the submit_form_reply action.

  1. Shortcode Identification: The plugin typically uses a shortcode like [happy_ticket_list] or [happy_ticket_form] to render the support system. (Inferred based on helpdesk plugin patterns).
  2. Setup: Create a page containing the helpdesk shortcode and create at least one ticket as a "Victim" (Admin).
  3. Navigation: Log in as the "Attacker" (Subscriber) and navigate to the helpdesk page.
  4. Extraction:
    • Use browser_eval to find the localized JS object.
    • Look for variables like happy_ajax, happy_vars, or happy_helpdesk_obj.
    • Target Variable (Inferred): window.happy_ajax?.nonce or window.happy_vars?.reply_nonce.

5. Exploitation Strategy

  1. Step 1: Environment Setup
    • Create an Admin user (Victim).
    • Create a Subscriber user (Attacker).
    • As Admin, create a support ticket. Note the post_id (this is the happy_topic_id).
  2. Step 2: Nonce Retrieval
    • Log in as the Subscriber.
    • Access the ticket dashboard page.
    • Extract the nonce from the JS context.
  3. Step 3: Unauthorized Reply
    • Use the http_request tool to send a POST request to admin-ajax.php.
    • Request Details:
      • URL: http://localhost:8080/wp-admin/admin-ajax.php
      • Method: POST
      • Headers: Content-Type: application/x-www-form-urlencoded, Cookie: [Subscriber Cookies]
      • Body Parameters:
        • action: submit_form_reply
        • happy_topic_id: [Target Ticket ID]
        • reply_msg: This is an unauthorized reply from a Subscriber.
        • security or _wpnonce: [Extracted Nonce]

6. Test Data Setup

# 1. Create a Subscriber user
wp user create attacker attacker@example.com --role=subscriber --user_pass=password

# 2. Create a "Victim" Ticket (Support tickets are usually a Custom Post Type, likely 'happy_ticket' or 'ticket')
# We need to identify the CPT. For this plan, we assume 'happy_ticket'.
wp post create --post_type=happy_ticket --post_title="Sensitive Support Issue" --post_content="Help me with my billing." --post_status=publish --post_author=1

# 3. Create a page with the helpdesk shortcode to load the JS/Nonces
wp post create --post_type=page --post_title="Support Center" --post_content="[happy_ticket_list]" --post_status=publish

7. Expected Results

  • The AJAX response should return a success message (e.g., {"success": true} or a rendered HTML fragment of the comment).
  • The Subscriber, who is neither the owner nor an agent for Ticket ID X, successfully appends data to Ticket ID X.

8. Verification Steps

# Check if a comment/reply was added to the target ticket ID
# Replies might be stored as standard WordPress comments or in a custom table
wp comment list --post_id=[TARGET_ID]

# Or, if using custom tables, query the database directly
wp db query "SELECT * FROM wp_happy_replies WHERE topic_id = [TARGET_ID]"

9. Alternative Approaches

  • Parameter Brute Force: If the nonce is not validated (common in "Missing Authorization" but "Valid CSRF" scenarios), attempt the request without the security parameter.
  • Role Elevation Check: If the reply mechanism allows attaching files or setting metadata, check if the Subscriber can use this unauthorized reply to perform XSS or change ticket status (e.g., status=closed).
  • Target Identification: If the CPT name is different, use wp post-type list to identify the correct helpdesk ticket post type.
Research Findings
Static analysis — not yet PoC-verified

Summary

The HAPPY – Helpdesk Support Ticket System plugin for WordPress (<= 1.0.9) contains a missing authorization vulnerability in its AJAX reply handling logic. This allows authenticated users, such as Subscribers, to post replies to any support ticket by manipulating the 'happy_topic_id' parameter, bypassing ownership and assignment restrictions.

Vulnerable Code

// In the plugin's AJAX handler registration
add_action('wp_ajax_submit_form_reply', array($this, 'submit_form_reply'));

Security Fix

--- a/happy-helpdesk-support-ticket-system.php
+++ b/happy-helpdesk-support-ticket-system.php
@@ -120,6 +120,11 @@
 	public function submit_form_reply() {
 		check_ajax_referer('happy_ajax_nonce', 'security');
 
+		$topic_id = isset($_POST['happy_topic_id']) ? intval($_POST['happy_topic_id']) : 0;
+		$ticket = get_post($topic_id);
+		if (!$ticket || ($ticket->post_author != get_current_user_id() && !current_user_can('manage_options'))) {
+			wp_die(__('Unauthorized access', 'happy-helpdesk-support-ticket-system'));
+		}
 		$reply_msg = isset($_POST['reply_msg']) ? sanitize_textarea_field($_POST['reply_msg']) : '';

Exploit Outline

An authenticated attacker with Subscriber-level access can exploit this vulnerability by first obtaining a valid AJAX nonce, typically found in localized JavaScript objects like 'happy_ajax' on ticket dashboard pages. The attacker then identifies a target ticket ID (happy_topic_id) that they do not own. By sending a POST request to '/wp-admin/admin-ajax.php' with the action 'submit_form_reply', the target ticket ID, the valid nonce, and a reply message, the attacker can successfully append a reply to the victim's ticket. The vulnerability exists because the plugin's backend handler does not verify if the current user is the author of the ticket or has administrative permissions before processing the submission.

Check if your site is affected.

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