My Tickets – Accessible Event Ticketing <= 2.1.1 - Missing Authorization
Description
The My Tickets – Accessible Event Ticketing plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 2.1.1. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v2.1.2
Source Code
WordPress.org SVN# Research Plan: CVE-2026-32492 Missing Authorization in My Tickets ## 1. Vulnerability Summary The **My Tickets** plugin for WordPress (versions <= 2.1.1) is vulnerable to **Missing Authorization** in its AJAX handlers. Specifically, the `mt_ajax_handler` function (and potentially others in `mt-aj…
Show full research plan
Research Plan: CVE-2026-32492 Missing Authorization in My Tickets
1. Vulnerability Summary
The My Tickets plugin for WordPress (versions <= 2.1.1) is vulnerable to Missing Authorization in its AJAX handlers. Specifically, the mt_ajax_handler function (and potentially others in mt-ajax.php) is registered for both authenticated (wp_ajax_) and unauthenticated (wp_ajax_nopriv_) users without adequate capability checks for certain internal functions.
The most likely vector involves the save_address functionality or the mt_ajax_load_model function, which allows unauthenticated users to perform actions or access data models that should be restricted. In version 2.1.1, the save_address function updates user metadata based on the current user object, which for unauthenticated users defaults to ID 0, potentially leading to database pollution or unauthorized metadata manipulation.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
mt_ajax_handler(forsave_address) ormt_ajax_load_model. - Authentication: Unauthenticated (via
wp_ajax_nopriv_mt_ajax_handler). - Preconditions:
- The plugin must be active.
- A valid nonce for the specific AJAX action must be obtained from a front-end page (e.g., an event
Summary
The My Tickets plugin for WordPress is vulnerable to Missing Authorization because several AJAX handlers, such as mt_ajax_handler and mt_ajax_load_model, are registered for unauthenticated users without internal capability checks. This allows unauthenticated attackers to perform unauthorized actions like updating user metadata or accessing restricted data models, provided they can obtain a valid security nonce from the site's front-end.
Vulnerable Code
// mt-ajax.php lines 224-225 (v2.1.1) add_action( 'wp_ajax_mt_ajax_handler', 'mt_ajax_handler' ); add_action( 'wp_ajax_nopriv_mt_ajax_handler', 'mt_ajax_handler' ); --- // mt-ajax.php lines 212-222 (v2.1.1) if ( 'save_address' === $_REQUEST['function'] ) { $post = array_map( 'sanitize_text_field', $_REQUEST['data'] ); $current_user = wp_get_current_user(); $saved = update_user_meta( $current_user->ID, '_mt_shipping_address', $post ); $response = array(); if ( $saved ) { $response['response'] = apply_filters( 'mt_save_address_success', __( 'Address updated.', 'my-tickets' ) ); } else { $response['response'] = apply_filters( 'mt_save_address_failure', __( 'Address not updated.', 'my-tickets' ) ); } wp_send_json( $response ); } --- // mt-ajax.php lines 230-244 (v2.1.1) function mt_ajax_load_model() { // verify nonce. if ( ! check_ajax_referer( 'mt-load-model', 'security', false ) ) { wp_send_json( array( 'response' => __( 'Invalid security response.', 'my-tickets' ), 'form' => '', ) ); } $model = ( in_array( $_REQUEST['model'], array( 'continuous', 'discrete', 'event' ), true ) ) ? sanitize_key( $_REQUEST['model'] ) : false; // ... logic continues ... } add_action( 'wp_ajax_mt_ajax_load_model', 'mt_ajax_load_model' ); add_action( 'wp_ajax_nopriv_mt_ajax_load_model', 'mt_ajax_load_model' );
Security Fix
@@ -178,6 +178,10 @@ text-align: end; } +.mt-order legend { + float: none; +} + .mt_cart th .mt-datetime { font-weight: 400; } @@ -81,6 +81,15 @@ $data = map_deep( $data, 'sanitize_text_field' ); // reformat request data to multidimensional array. $cart = mt_get_cart(); + $lock = 'mt_add_to_cart_lock_' . sanitize_text_field( $_REQUEST['mt-cart-nonce'] ); + if ( get_transient( $lock ) ) { + $return = array( + 'response' => esc_html__( 'Another transaction is currently processing. Please try again shortly.', 'my-tickets' ), + 'success' => 0, + ); + wp_send_json( $return ); + } + set_transient( $lock, 1, 5 ); foreach ( $data as $k => $d ) { if ( 'mt_tickets' === $k ) { @@ -163,6 +172,7 @@ 'event_id' => $submit['mt_event_id'], 'data' => $count, ); + delete_transient( $lock ); wp_send_json( $return ); } if ( 'save_address' === $_REQUEST['function'] ) { @@ -769,7 +769,7 @@ if ( function_exists( 'mc_draw_template' ) ) { return mc_draw_template( $data, $template ); } else { - $template = stripcslashes( $template ); + $template = wp_unslash( $template ); // If there are no brace characters, there is nothing to replace. if ( strpos( $template, '{' ) === false ) { return trim( $template ); @@ -802,7 +802,7 @@ } } } else { // don't do preg match (never required for RSS). - $template = stripcslashes( str_replace( '{' . $key . '}', $value, $template ) ); + $template = wp_unslash( str_replace( '{' . $key . '}', $value, $template ) ); } } // end {$key check. } @@ -27,7 +27,7 @@ $nonce = isset( $_POST['_wpnonce'] ) ? $_POST['_wpnonce'] : false; $verify = wp_verify_nonce( $nonce, 'mt-verify-email' ); $email = sanitize_text_field( $_POST['mt-verify-email'] ); - $is_verified = ( $verify && $email === get_post_meta( $receipt->ID, '_email', true ) ) ? true : false; + $is_verified = ( $verify && get_post_meta( $receipt->ID, '_email', true ) === $email ) ? true : false; } $cookie_receipt = ( isset( $_COOKIE['mt_purchase_receipt'] ) ) ? $_COOKIE['mt_purchase_receipt'] : false; // Allow conditions: within 10 minutes of purchase & browser has a matching cookie; current user can view reports; user has verified email. @@ -17,11 +17,11 @@ * License: GPL-2.0+ * License URI: http://www.gnu.org/license/gpl-2.0.txt * Domain Path: lang - * Version: 2.1.1 + * Version: 2.1.2 */ /* - Copyright 2014-2025 Joe Dolson (email : joe@joedolson.com) + Copyright 2014-2026 Joe Dolson (email : joe@joedolson.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -44,7 +44,7 @@ * @return string Current My Tickets version. */ function mt_get_current_version() { - $mt_version = '2.1.1'; + $mt_version = '2.1.2'; return $mt_version; }
Exploit Outline
The exploit methodology involves targeting the WordPress AJAX endpoint (/wp-admin/admin-ajax.php) using actions registered for unauthenticated users. An attacker first navigates to a front-end event page to extract a valid security nonce (e.g., mt-cart-nonce or mt-load-model). Once obtained, the attacker sends a POST request to the AJAX endpoint. For example, by specifying the action 'mt_ajax_handler' and function 'save_address', the attacker can attempt to manipulate user metadata despite being unauthenticated. Alternatively, using 'mt_ajax_load_model' allows the attacker to trigger data model loading logic that is intended to be protected by authorization checks.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.