CVE-2026-4109

Eventin – Events Calendar, Event Booking, Ticket & Registration (AI Powered) <= 4.1.8 Missing Authorization to Authenticated (Subscriber+) Order Information Exposure

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
4.1.9
Patched in
1d
Time to patch

Description

The Eventin – Events Calendar, Event Booking, Ticket & Registration (AI Powered) plugin for WordPress is vulnerable to unauthorized access of data due to a improper capability check on the get_item_permissions_check() function in all versions up to, and including, 4.1.8. This makes it possible for authenticated attackers, with Subscriber-level access and above, to read arbitrary order data including customer PII (name, email, phone) by iterating order IDs.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=4.1.8
PublishedApril 13, 2026
Last updatedApril 14, 2026
Affected pluginwp-event-solution

What Changed in the Fix

Changes introduced in v4.1.9

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Vulnerability Research Plan: CVE-2026-4109 - Eventin Order Information Exposure ## 1. Vulnerability Summary The **Eventin** plugin (versions <= 4.1.8) contains a **Missing Authorization** vulnerability within its REST API implementation. Specifically, the `get_item_permissions_check()` function (…

Show full research plan

Vulnerability Research Plan: CVE-2026-4109 - Eventin Order Information Exposure

1. Vulnerability Summary

The Eventin plugin (versions <= 4.1.8) contains a Missing Authorization vulnerability within its REST API implementation. Specifically, the get_item_permissions_check() function (likely within a class extending WP_REST_Controller for orders or attendees) fails to properly restrict access to order data. This allows any authenticated user, including those with the Subscriber role, to retrieve sensitive order details—including Customer PII (Name, Email, Phone)—by directly querying the REST API and iterating through Order IDs.

2. Attack Vector Analysis

  • Endpoint: WordPress REST API.
  • Likely Route: /wp-json/eventin/v1/orders/(?P<id>[\d]+) or /wp-json/eventin/v1/attendees/(?P<id>[\d]+) (Namespace: eventin/v1 inferred from standard plugin architecture).
  • HTTP Method: GET.
  • Authentication: Authenticated (Subscriber level or higher).
  • Payload: Path parameter containing the target order_id.
  • Preconditions: At least one order/booking must exist in the system for data to be exposed.

3. Code Flow

  1. Registration: The plugin registers REST routes during the rest_api_init hook. One of these routes handles order retrieval.
  2. Request Initiation: A Subscriber user sends a GET request to /wp-json/eventin/v1/orders/<ID>.
  3. Permission Check: The WordPress REST API calls the permission_callback defined for that route. In this plugin, it points to get_item_permissions_check().
  4. Vulnerable Logic: Inside get_item_permissions_check(), the code likely checks for a generic capability like read or simply verifies is_user_logged_in(), rather than checking if the user is an admin or if the order belongs specifically to the requesting user.
  5. Information Disclosure: Because the check passes for Subscribers, the controller proceeds to get_item(), fetches the order data (which includes PII), and returns it in the JSON response.

4. Nonce Acquisition Strategy

The WordPress REST API requires a _wpnonce parameter or X-WP-Nonce header for authenticated requests to prevent CSRF, even for some GET requests if the session is cookie-based.

  1. Identify Trigger: The base/Enqueue/admin.php file enqueues several scripts like etn-app-index and etn-dashboard. These typically load the WordPress REST environment.
  2. Create Page: A Subscriber user can access the standard WordPress dashboard (/wp-admin/index.php).
  3. Execute Extraction:
    • Navigate to /wp-admin/index.php as the Subscriber.
    • The REST nonce is globally available in the wpApiSettings object on most admin pages or can be extracted from the localized data of the plugin's scripts.
    • JS Command: browser_eval("wpApiSettings.nonce") or browser_eval("localized_data_obj.nonce") (based on etn_get_locale_data() seen in base/Enqueue/admin.php).
  4. Action String: The nonce action used for the REST API is always wp_rest.

5. Exploitation Strategy

  1. Preparation: Log in as a Subscriber user.
  2. Nonce Retrieval: Use browser_eval to get the wp_rest nonce.
  3. Discovery: Identify the REST namespace.
    • Request GET /wp-json/ and look for namespaces containing "eventin".
  4. Targeting: Access the order endpoint.
    • Request Method: GET
    • URL: http://localhost:8080/wp-json/eventin/v1/orders/1 (Increment IDs to find data).
    • Headers:
      • X-WP-Nonce: [EXTRACTED_NONCE]
      • Cookie: [SUBSCRIBER_COOKIES]
  5. Iteration: Use a script or loop to iterate IDs from 1 to 100.

6. Test Data Setup

To demonstrate the PII exposure, the environment must contain an order:

  1. Install Eventin: Ensure the plugin (v4.1.8) is active.
  2. Create Event: Use WP-CLI to create an event post type.
    • wp post create --post_type=etn-event --post_title="Sensitive Event" --post_status=publish
  3. Create Order: As Admin, create a manual booking/order or use the front-end to book a ticket for a dummy user "Victim User" with email victim@example.com and phone 555-0199.
  4. Create Attacker: Create a user with the Subscriber role.
    • wp user create attacker attacker@example.com --role=subscriber --user_pass=password123

7. Expected Results

  • Successful Exploit: The server returns a 200 OK response with a JSON body containing fields like customer_name, customer_email, customer_phone, and order_total for an order ID that does not belong to the Subscriber.
  • Vulnerable Response Snippet:
    {
      "id": 1,
      "order_details": {
        "full_name": "Victim User",
        "email": "victim@example.com",
        "phone": "555-0199"
      }
    }
    

8. Verification Steps

  1. HTTP Check: Confirm the response code is 200 and the PII is present in the JSON output.
  2. Database Correlation: Verify the returned data matches the entries in the wp_posts (post_type etn-order or similar) and wp_postmeta tables.
    • wp db query "SELECT * FROM wp_postmeta WHERE post_id = 1"
  3. Capability Check: Confirm the "attacker" user indeed only has the subscriber role and should not normally see other users' orders.
    • wp user get attacker --field=roles

9. Alternative Approaches

  • Alternative Endpoints: If /orders/ is not the route, check /attendees/ or /tickets/. The core issue is the get_item_permissions_check in the controller handling any booking-related data.
  • Export Functionality: Check if the CSV/JSON exporters defined in base/Exporter/ are reachable via an unprivileged AJAX or REST action. The description specifically mentions get_item_permissions_check(), which is strongly associated with the REST API.
  • Public REST: Check if the endpoint allows access even without a nonce (though authenticated) if the permission_callback returns true.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Eventin plugin for WordPress (versions up to 4.1.8) fails to perform adequate authorization checks within its REST API controller for order retrieval. This flaw allows authenticated users, including those with Subscriber-level roles, to access sensitive customer PII such as names, email addresses, and phone numbers by iterating through order IDs via the API.

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/wp-event-solution/4.1.8/base/Enqueue/admin.php /home/deploy/wp-safety.org/data/plugin-versions/wp-event-solution/4.1.9/base/Enqueue/admin.php
--- /home/deploy/wp-safety.org/data/plugin-versions/wp-event-solution/4.1.8/base/Enqueue/admin.php	2026-03-17 11:12:52.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wp-event-solution/4.1.9/base/Enqueue/admin.php	2026-04-08 10:11:10.000000000 +0000
@@ -134,7 +134,7 @@
         wp_localize_script( 'etn-onboard-index', 'localized_data_obj', $localize_data );
         wp_enqueue_style( 'etn-icon' );
         // Enque block editor style in events create and edit pages only
-        if ( isset( $_GET['page'] ) && $_GET['page'] === 'eventin' ) {
+        if ( isset( $_GET['page'] ) && $_GET['page'] === 'eventin' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- admin script enqueue condition; page param compared to a literal string only.
             wp_enqueue_style( 'wp-block-editor' );
         }
     }
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/wp-event-solution/4.1.8/base/Enqueue/register.php /home/deploy/wp-safety.org/data/plugin-versions/wp-event-solution/4.1.9/base/Enqueue/register.php
--- /home/deploy/wp-safety.org/data/plugin-versions/wp-event-solution/4.1.8/base/Enqueue/register.php	2026-03-17 11:12:52.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wp-event-solution/4.1.9/base/Enqueue/register.php	2026-04-08 10:11:10.000000000 +0000
@@ -194,7 +194,7 @@
         }
 
         // Parse the URL
-        $url_parts = parse_url( $url );
+        $url_parts = wp_parse_url( $url );
 
         // Check if the URL has a path component
         if ( ! isset( $url_parts['path'] ) ) {
@@ -204,7 +204,7 @@
         $clean_path = str_replace( '.js', '.asset.php', $url_parts['path'] );
 
         // Get the file path from the URL path
-        $file_path = $_SERVER['DOCUMENT_ROOT'] . $clean_path;
+        $file_path = ( isset( $_SERVER['DOCUMENT_ROOT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['DOCUMENT_ROOT'] ) ) : '' ) . $clean_path; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- DOCUMENT_ROOT is a trusted server variable used only to build a file path, not output or stored.
 
         // Check if the file exists
         if ( ! file_exists( $file_path ) ) {

Exploit Outline

1. Log in to the WordPress site as an authenticated user (e.g., Subscriber role). 2. Obtain a valid REST API nonce from the WordPress dashboard, typically available in the 'wpApiSettings.nonce' JavaScript object. 3. Identify a target order ID by observing existing bookings or guessing a numerical sequence. 4. Send an authenticated GET request to the Eventin REST API endpoint: '/wp-json/eventin/v1/orders/<ID>', passing the nonce in the 'X-WP-Nonce' header. 5. The API will respond with a JSON object containing sensitive PII for the order, including full_name, email, and phone, regardless of whether the order belongs to the requesting user. 6. Automate this process by iterating through numerical IDs to extract a full database of customer information.

Check if your site is affected.

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