[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fCDvOYFwjlXK3lAyMzOK7bvc6eHufoOyi2ysiy-CnLok":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":26,"research_verified":27,"research_rounds_completed":28,"research_plan":29,"research_summary":30,"research_vulnerable_code":31,"research_fix_diff":32,"research_exploit_outline":33,"research_model_used":34,"research_started_at":35,"research_completed_at":36,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":27,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":27,"source_links":37},"CVE-2026-39518","eventprime-events-calendar-bookings-and-tickets-authenticated-subscriber-insecure-direct-object-reference","EventPrime – Events Calendar, Bookings and Tickets \u003C= 4.3.0.0 - Authenticated (Subscriber+) Insecure Direct Object Reference","The EventPrime – Events Calendar, Bookings and Tickets plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 4.3.0.0 due to missing validation on a user controlled key. This makes it possible for authenticated attackers, with Subscriber-level access and above, to perform unauthorized actions.","eventprime-event-calendar-management",null,"\u003C=4.3.0.0","4.3.0.1","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Authorization Bypass Through User-Controlled Key","2026-04-20 00:00:00","2026-04-30 15:48:25",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F77608ee4-1917-4b2c-8acf-5d6087c5ae7a?source=api-prod",11,[22,23,24,25],"event-prime.php","includes\u002Fclass-ep-ajax.php","includes\u002Fclass-eventprime-functions.php","readme.txt","researched",false,3,"# Exploitation Research Plan - CVE-2026-39518\n\n## 1. Vulnerability Summary\nThe **EventPrime** plugin (\u003C= 4.3.0.0) contains an **Insecure Direct Object Reference (IDOR)** vulnerability in its AJAX handling logic, specifically within the `EventM_Ajax_Service::cancel_current_booking_process` method (and potentially others like `save_checkout_field`). The `cancel_current_booking_process` function accepts an `event_id` and `ticket_data` directly from user input and modifies the `em_seat_data` post meta of the specified event without verifying if the current user has permission to manage that event or if they are the owner of the booking process being cancelled. This allows a Subscriber-level user to manipulate the seating status (e.g., releasing \"held\" seats) of any event.\n\n## 2. Attack Vector Analysis\n- **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Action**: `ep_cancel_current_booking_process` (Note: Actions in this plugin are typically prefixed with `ep_` based on the method name).\n- **HTTP Method**: `POST`\n- **Payload Parameters**:\n    - `action`: `ep_cancel_current_booking_process`\n    - `security`: A valid WordPress nonce for the action `event-registration-form-nonce`.\n    - `event_id`: The ID of the target event to manipulate.\n    - `ticket_data`: A JSON string representing the seats to \"cancel\" (revert from 'hold' to 'general').\n- **Authentication**: Required (Subscriber level or higher).\n- **Preconditions**: The target event must have seating data stored in the `em_seat_data` post meta.\n\n## 3. Code Flow\n1. **Entry Point**: The AJAX request is received by `admin-ajax.php` and dispatched to `EventM_Ajax_Service::cancel_current_booking_process`.\n2. **Nonce Check**: `wp_verify_nonce( $_POST['security'], 'event-registration-form-nonce' )` is called. This nonce is available to any user viewing an event page.\n3. **Parameter Extraction**: \n    - `$event_id = absint( $_POST['event_id'] );` (User-controlled object reference).\n    - `$ticket_data = json_decode( stripslashes( $_POST['ticket_data'] ) );`\n4. **Data Retrieval**: `$event_seat_data = get_post_meta( $event_id, 'em_seat_data', true );`. It fetches meta for the *provided* ID without checking permissions.\n5. **Modification Logic**: The code iterates through the user-provided `$ticket_data` and matches `area_id` and seat `uid` (row\u002Fcolumn). If a seat is found with type `hold`, it is reset:\n   ```php\n   if( $seat->type == 'hold' ) {\n       $seat->type = 'general';\n       $seat->hold_time = '';\n       \u002F\u002F ...\n   }\n   ```\n6. **Sink**: `update_post_meta( $event_id, 'em_seat_data', maybe_serialize( $event_seat_data ) );` saves the modified data back to the database for the target event.\n\n## 4. Nonce Acquisition Strategy\nThe nonce `event-registration-form-nonce` is required. It is generated using `wp_create_nonce('event-registration-form-nonce')` and is typically localized for the frontend booking scripts.\n\n1. **Identify Script Loading**: Create an event and enable bookings.\n2. **Navigate**: Use `browser_navigate` to visit the event's permalink.\n3. **Extract Nonce**: Use `browser_eval` to extract the nonce from the `ep_ajax_obj` global variable:\n   ```javascript\n   \u002F\u002F Verbatim from common EventPrime localization patterns\n   window.ep_ajax_obj?.security \n   ```\n4. **Alternative**: If not in `ep_ajax_obj`, check for a hidden input field:\n   ```javascript\n   document.querySelector('input[name=\"security\"]')?.value\n   ```\n\n## 5. Exploitation Strategy\n### Step 1: Data Setup\n1. Create a \"Target Event\" (ID $X$) as Admin.\n2. Manually set the `em_seat_data` meta for Event $X$ to simulate a seat on hold.\n3. Create a Subscriber user.\n\n### Step 2: Payload Construction\nConstruct a `ticket_data` JSON that targets a specific area and seat:\n```json\n[\n  {\n    \"seats\": [\n      {\n        \"area_id\": \"1\",\n        \"seat_data\": [\n          {\n            \"uid\": \"0-0\"\n          }\n        ]\n      }\n    ]\n  }\n]\n```\n\n### Step 3: Execution\nPerform the attack as the Subscriber user using the `http_request` tool:\n- **URL**: `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Method**: `POST`\n- **Body**:\n  ```\n  action=ep_cancel_current_booking_process&security=[NONCE]&event_id=[TARGET_EVENT_ID]&ticket_data=[JSON_PAYLOAD]\n  ```\n- **Content-Type**: `application\u002Fx-www-form-urlencoded`\n\n## 6. Test Data Setup\nUse WP-CLI","The EventPrime plugin for WordPress is vulnerable to an Insecure Direct Object Reference (IDOR) via several AJAX endpoints because it fails to perform adequate authorization checks on user-supplied IDs. This allows authenticated attackers with Subscriber-level access or higher to perform unauthorized actions such as releasing event seats, modifying checkout fields, and accessing or updating booking information belonging to other users or events.","\u002F\u002F File: includes\u002Fclass-ep-ajax.php\n\u002F\u002F Lines 11-82 (approx.)\npublic function cancel_current_booking_process() {\n    \u002F\u002F Add security checks \n    if( wp_verify_nonce( $_POST['security'], 'event-registration-form-nonce' ) ) {\n        $event_id = absint( $_POST['event_id'] ); \n        $ticket_data = json_decode( stripslashes( $_POST['ticket_data'] ) );\n\n        $event_seat_data = get_post_meta( $event_id, 'em_seat_data', true );\n        if( ! empty( $event_seat_data ) ) { \n            \u002F\u002F ... (Logic to iterate through ticket_data and reset seats) ...\n           $update =  update_post_meta( $event_id, 'em_seat_data', maybe_serialize( $event_seat_data ) );\n           wp_send_json_success($update);\n        }\n    }\n}\n\n---\n\n\u002F\u002F File: includes\u002Fclass-ep-ajax.php\n\u002F\u002F Lines 87-94 (approx.)\npublic function save_checkout_field() {\n    check_ajax_referer( 'save-checkout-fields', 'security' );\n\n    $response = array();\n    parse_str( wp_unslash( $_POST['data'] ), $data );\n    \u002F\u002F ... (logic to insert or update checkout fields in database) ...\n}\n\n---\n\n\u002F\u002F File: includes\u002Fclass-ep-ajax.php\n\u002F\u002F Lines 2581-2610 (approx.)\npublic function update_event_booking_action() {\n    $sanitizer = new EventPrime_sanitizer;\n    parse_str( wp_unslash( $_POST['data'] ), $data );\n    $ep_functions = new Eventprime_Basic_Functions;\n    if( wp_verify_nonce( $data['ep_update_event_booking_nonce'], 'ep_update_event_booking' ) ) {\n        $ep_event_booking_id = ( ! empty( $data['ep_event_booking_id'] ) ? $data['ep_event_booking_id'] : '' );\n        if( ! empty( $ep_event_booking_id ) ) {\n            \u002F\u002F ... (Fetches and updates attendee meta without checking if the user owns the booking) ...\n            update_post_meta( $ep_event_booking_id, 'em_attendee_names', $ep_booking_attendde_field );","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Feventprime-event-calendar-management\u002F4.3.0.0\u002Fincludes\u002Fclass-ep-ajax.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Feventprime-event-calendar-management\u002F4.3.0.1\u002Fincludes\u002Fclass-ep-ajax.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Feventprime-event-calendar-management\u002F4.3.0.0\u002Fincludes\u002Fclass-ep-ajax.php\t2026-03-02 05:59:32.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Feventprime-event-calendar-management\u002F4.3.0.1\u002Fincludes\u002Fclass-ep-ajax.php\t2026-03-05 09:32:14.000000000 +0000\n@@ -77,11 +77,14 @@\n-    public function save_checkout_field() {\n-        check_ajax_referer( 'save-checkout-fields', 'security' );\n-\n-        $response = array();\n-        parse_str( wp_unslash( $_POST['data'] ), $data );\n+    public function save_checkout_field() {\n+        if ( ! current_user_can( 'manage_options' ) ) {\n+            wp_send_json_error( array( 'message' => esc_html__( 'You are not allowed to manage checkout fields.', 'eventprime-event-calendar-management' ) ) );\n+        }\n+        check_ajax_referer( 'save-checkout-fields', 'security' );\n+\n+        $response = array();\n+        parse_str( wp_unslash( $_POST['data'] ?? '' ), $data );\n@@ -135,9 +138,12 @@\n-    \u002F\u002F delete the checkout field\n-    public function delete_checkout_field(){\n-        check_ajax_referer( 'delete-checkout-fields', 'security' );\n+    \u002F\u002F delete the checkout field\n+    public function delete_checkout_field(){\n+        if ( ! current_user_can( 'manage_options' ) ) {\n+            wp_send_json_error( array( 'message' => esc_html__( 'You are not allowed to manage checkout fields.', 'eventprime-event-calendar-management' ) ) );\n+        }\n+        check_ajax_referer( 'delete-checkout-fields', 'security' );\n@@ -2578,37 +2584,71 @@\n-    public function update_event_booking_action() {\n-        $sanitizer = new EventPrime_sanitizer;\n-        parse_str( wp_unslash( $_POST['data'] ), $data );\n-        $ep_functions = new Eventprime_Basic_Functions;\n-        if( wp_verify_nonce( $data['ep_update_event_booking_nonce'], 'ep_update_event_booking' ) ) {\n-            $ep_event_booking_id = ( ! empty( $data['ep_event_booking_id'] ) ? $data['ep_event_booking_id'] : '' );\n-            if( ! empty( $ep_event_booking_id ) ) {\n-                $booking_controller = new EventPrime_Bookings;\n-                $single_booking = $booking_controller->load_booking_detail( $ep_event_booking_id );\n-                if( ! empty( $single_booking ) ) {\n-                    if( ! empty( $data['ep_booking_attendee_fields'] ) ) {\n-                        $ep_booking_attendde_field = $sanitizer->sanitize($data['ep_booking_attendee_fields']);\n-                        update_post_meta( $ep_event_booking_id, 'em_attendee_names', $ep_booking_attendde_field );\n-                    }\n-                }\n-                wp_send_json_success( array( 'message' => esc_html__( 'Booking Updated Successfully.', 'eventprime-event-calendar-management' ), 'redirect_url' => esc_url( $ep_functions->ep_get_custom_page_url( 'profile_page' ) ) ) );\n-            } else{\n-                wp_send_json_error( array( 'message' => esc_html__( 'Booking id can\\'t be null. Please refresh the page and try again later.', 'eventprime-event-calendar-management' ) ) );\n-            }\n-        } else{\n-            wp_send_json_error( array( 'message' => esc_html__( 'Security check failed. Please refresh the page and try again later.', 'eventprime-event-calendar-management' ) ) );\n-        }\n-    }\n+\n+    public function update_event_booking_action() {\n+        $sanitizer = new EventPrime_sanitizer;\n+        parse_str( wp_unslash( $_POST['data'] ?? '' ), $data );\n+        $ep_functions = new Eventprime_Basic_Functions;\n+        if ( empty( $data['ep_update_event_booking_nonce'] ) || ! wp_verify_nonce( $data['ep_update_event_booking_nonce'], 'ep_update_event_booking' ) ) {\n+            wp_send_json_error( array( 'message' => esc_html__( 'Security check failed. Please refresh the page and try again later.', 'eventprime-event-calendar-management' ) ) );\n+        }\n+\n+        if ( ! is_user_logged_in() ) {\n+            wp_send_json_error( array( 'message' => esc_html__( 'You are not authorised to update this booking.', 'eventprime-event-calendar-management' ) ) );\n+        }\n+\n+        $ep_event_booking_id = ( ! empty( $data['ep_event_booking_id'] ) ? absint( $data['ep_event_booking_id'] ) : 0 );\n+        if( ! empty( $ep_event_booking_id ) ) {\n+            $booking_post = get_post( $ep_event_booking_id );\n+            if ( empty( $booking_post ) || $booking_post->post_type !== 'em_booking' ) {\n+                wp_send_json_error( array( 'message' => esc_html__( 'Invalid booking id. Please refresh the page and try again later.', 'eventprime-event-calendar-management' ) ) );\n+            }\n+\n+            $current_user_id = get_current_user_id();\n+            $booking_user_id = (int) get_post_meta( $ep_event_booking_id, 'em_user', true );\n+            $can_update_booking = current_user_can( 'edit_post', $ep_event_booking_id )\n+                || ( $booking_user_id > 0 && $booking_user_id === $current_user_id );\n+\n+            if ( ! $can_update_booking ) {\n+                wp_send_json_error( array( 'message' => esc_html__( 'You are not authorised to update this booking.', 'eventprime-event-calendar-management' ) ) );\n+            }\n+\n+            $booking_controller = new EventPrime_Bookings;\n+            $single_booking = $booking_controller->load_booking_detail( $ep_event_booking_id );\n+            if( ! empty( $single_booking ) ) {\n+                if( ! empty( $data['ep_booking_attendee_fields'] ) ) {\n+                    $ep_booking_attendde_field = $sanitizer->sanitize($data['ep_booking_attendee_fields']);\n+                    update_post_meta( $ep_event_booking_id, 'em_attendee_names', $ep_booking_attendde_field );\n+                }\n+            }\n+            wp_send_json_success( array( 'message' => esc_html__( 'Booking Updated Successfully.', 'eventprime-event-calendar-management' ), 'redirect_url' => esc_url( $ep_functions->ep_get_custom_page_url( 'profile_page' ) ) ) );\n+        } else{\n+            wp_send_json_error( array( 'message' => esc_html__( 'Booking id can\\'t be null. Please refresh the page and try again later.', 'eventprime-event-calendar-management' ) ) );\n+        }\n+    }","To exploit this vulnerability, an attacker must be authenticated (e.g., as a Subscriber). They first obtain a valid security nonce from the frontend (such as `event-registration-form-nonce` or `ep_update_event_booking`), which is typically available in localized JavaScript objects or hidden input fields on event pages. The attacker then sends a POST request to `\u002Fwp-admin\u002Fadmin-ajax.php`. \n\nFor example, to manipulate event seating via the `ep_cancel_current_booking_process` action, the attacker provides the `event_id` of the target event and a JSON-formatted `ticket_data` payload specifying the seats to reset. Because the backend code uses `get_post_meta` and `update_post_meta` using the user-provided `event_id` without verifying the user's permissions or relationship to the event, the attacker can effectively release 'held' seats for any event on the site. Similar methodologies apply to endpoints managing checkout fields or booking details.","gemini-3-flash-preview","2026-05-04 19:56:10","2026-05-04 19:57:13",{"type":38,"vulnerable_version":39,"fixed_version":11,"vulnerable_browse":40,"vulnerable_zip":41,"fixed_browse":42,"fixed_zip":43,"all_tags":44},"plugin","4.3.0.0","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Feventprime-event-calendar-management\u002Ftags\u002F4.3.0.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Feventprime-event-calendar-management.4.3.0.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Feventprime-event-calendar-management\u002Ftags\u002F4.3.0.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Feventprime-event-calendar-management.4.3.0.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Feventprime-event-calendar-management\u002Ftags"]