Event Tickets and Registration <= 5.27.5 - Missing Authorization
Description
The Event Tickets and Registration plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 5.27.5. 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 v5.27.6.1
Source Code
WordPress.org SVNThis research plan targets **CVE-2026-42662**, a missing authorization vulnerability in the **Event Tickets and Registration** plugin. The vulnerability allows unauthenticated attackers to manipulate orders via the plugin's REST API endpoints for PayPal and Square commerce gateways. ### 1. Vulnerab…
Show full research plan
This research plan targets CVE-2026-42662, a missing authorization vulnerability in the Event Tickets and Registration plugin. The vulnerability allows unauthenticated attackers to manipulate orders via the plugin's REST API endpoints for PayPal and Square commerce gateways.
1. Vulnerability Summary
The Order_Endpoint classes for both PayPal and Square gateways register REST API routes with 'permission_callback' => '__return_true'. This explicitly allows unauthenticated access to the endpoints. While unauthenticated order creation is often intended for guest checkouts, the endpoints for updating and deleting (failing) orders also use the same permissive callback without secondary ownership or capability checks within the handler functions.
2. Attack Vector Analysis
- Endpoints:
- PayPal:
DELETE /wp-json/tec/v1/commerce/paypal/order/{order_id} - PayPal:
POST /wp-json/tec/v1/commerce/paypal/order/{order_id} - Square:
DELETE /wp-json/tec/v1/commerce/square/order/{order_id}
- PayPal:
- Vulnerable Parameter:
order_id(Gateway-specific order identifier string). - Authentication: None required (
PR:N). - Preconditions:
- The "Tickets Commerce" feature must be enabled.
- The PayPal or Square gateway must be configured.
- A valid Gateway Order ID must be known (can be obtained by initiating a guest order).
3. Code Flow
- Registration: In
src/Tickets/Commerce/Gateways/PayPal/REST/Order_Endpoint.php, theregister()method
Summary
The Event Tickets and Registration plugin for WordPress fails to properly restrict access to its PayPal and Square order management REST API endpoints. Unauthenticated attackers can exploit this by sending requests to update or cancel orders using valid gateway order IDs, leading to unauthorized order state manipulation and the potential leak of sensitive order data through verbose error responses.
Vulnerable Code
// src/Tickets/Commerce/Gateways/PayPal/REST/Order_Endpoint.php public function register() { $namespace = tribe( 'tickets.rest-v1.main' )->get_events_route_namespace(); $documentation = tribe( 'tickets.rest-v1.endpoints.documentation' ); register_rest_route( $namespace, $this->get_endpoint_path(), [ 'methods' => WP_REST_Server::CREATABLE, 'args' => $this->create_order_args(), 'callback' => [ $this, 'handle_create_order' ], 'permission_callback' => '__return_true', // Vulnerable permission check ] ); register_rest_route( $namespace, $this->get_endpoint_path() . '/(?P<order_id>[0-9a-zA-Z]+)', [ 'methods' => WP_REST_Server::CREATABLE, 'args' => $this->update_order_args(), 'callback' => [ $this, 'handle_update_order' ], 'permission_callback' => '__return_true', // Vulnerable permission check ] ); register_rest_route( $namespace, $this->get_endpoint_path() . '/(?P<order_id>[0-9a-zA-Z]+)', [ 'methods' => WP_REST_Server::DELETABLE, 'args' => $this->fail_order_args(), 'callback' => [ $this, 'handle_fail_order' ], 'permission_callback' => '__return_true', // Vulnerable permission check ] ); $documentation->register_documentation_provider( $this->get_endpoint_path(), $this ); } --- // src/Tickets/Commerce/Gateways/PayPal/REST/Order_Endpoint.php // Error responses leak the $order object or gateway payloads to unauthenticated users if ( ! $order ) { return new WP_Error( 'tec-tc-gateway-paypal-failed-creating-order', $messages['failed-creating-order'], $order ); }
Security Fix
@@ -122,7 +125,7 @@ $order = tribe( Order::class )->create_from_cart( tribe( Gateway::class ), $purchaser ); if ( ! $order ) { - return new WP_Error( 'tec-tc-gateway-paypal-failed-creating-order', $messages['failed-creating-order'], $order ); + return new WP_Error( 'tec-tc-gateway-paypal-failed-creating-order', $messages['failed-creating-order'] ); } $unit = [ @@ -152,7 +155,7 @@ $paypal_order = tribe( Client::class )->create_order( $unit ); if ( empty( $paypal_order['id'] ) || empty( $paypal_order['create_time'] ) ) { - return new WP_Error( 'tec-tc-gateway-paypal-failed-creating-order', $messages['failed-creating-order'], $order ); + return new WP_Error( 'tec-tc-gateway-paypal-failed-creating-order', $messages['failed-creating-order'] ); } $debug_header = tribe( Client::class )->get_debug_header(); @@ -327,7 +331,10 @@ 'gateway_payload' => $paypal_capture_response, ] ); - return new WP_Error( 'tec-tc-gateway-paypal-failed-capture', $messages['failed-capture'], $paypal_capture_response ); + return new WP_Error( 'tec-tc-gateway-paypal-failed-capture', $messages['failed-capture'], [ + 'name' => Arr::get( $paypal_capture_response, 'name' ), + 'details' => Arr::get( $paypal_capture_response, 'details', [] ), + ] ); } $response['success'] = true; @@ -382,7 +390,7 @@ $status = tribe( Status::class )->convert_to_commerce_status( $paypal_order_status ); if ( ! $status ) { - return new WP_Error( 'tec-tc-gateway-paypal-invalid-capture-status', $messages['invalid-capture-status'], $paypal_order_response ); + return new WP_Error( 'tec-tc-gateway-paypal-invalid-capture-status', $messages['invalid-capture-status'] ); } $updated = tribe( Order::class )->modify_status( $order->ID, $status->get_slug(), [ @@ -432,7 +441,7 @@ $messages = $this->get_error_messages(); if ( ! $order ) { - return new WP_Error( 'tec-tc-gateway-paypal-nonexistent-order-id', null, $order ); + return new WP_Error( 'tec-tc-gateway-paypal-nonexistent-order-id', null ); } $failed_reason = $request->get_param( 'failed_reason' ); @@ -441,13 +450,16 @@ $failed_status = 'not-completed'; } + $allowed_failure_statuses = [ Not_Completed::SLUG, Denied::SLUG, Voided::SLUG ]; + + if ( ! in_array( $failed_status, $allowed_failure_statuses, true ) ) { + return new WP_Error( 'tec-tc-gateway-paypal-invalid-failed-status', null ); + } + $status = tribe( Status_Handler::class )->get_by_slug( $failed_status ); if ( ! $status ) { - return new WP_Error( 'tec-tc-gateway-paypal-invalid-failed-status', null, [ - 'failed_status' => $failed_status, - 'failed_reason' => $failed_reason - ] ); + return new WP_Error( 'tec-tc-gateway-paypal-invalid-failed-status', null ); }
Exploit Outline
An unauthenticated attacker can exploit this vulnerability by targeting the REST API endpoints registered for the Tickets Commerce PayPal and Square gateways. The attacker first obtains a valid Gateway Order ID (for example, by initiating a guest checkout session). Using this ID, the attacker sends a DELETE request to `/wp-json/tec/v1/commerce/paypal/order/{order_id}` or its Square equivalent. Because the endpoints use `__return_true` as a permission callback and lack secondary ownership checks, the request is processed, allowing the attacker to force the order into a failure state (e.g., 'denied' or 'voided'). Furthermore, by purposefully sending malformed requests, the attacker can trigger error responses that include serialized Order objects or gateway payloads, exposing sensitive internal transaction data.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.