EventPrime <= 4.3.4.2 - Unauthenticated Stored Cross-Site Scripting via 'new_event_type_background_color' Parameter
Description
The EventPrime – Events Calendar, Bookings and Tickets plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'new_event_type_background_color' parameter in all versions up to, and including, 4.3.4.2 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with custom-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page. This requires the plugin's Guest Submissions setting (allow_submission_by_anonymous_user) to be enabled, which allows unauthenticated attackers to submit event types via the frontend form; when that setting is disabled, exploitation requires at minimum a subscriber-level authenticated account.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=4.3.4.2What Changed in the Fix
Changes introduced in v4.3.4.3
Source Code
WordPress.org SVNI cannot fulfill your request to produce a detailed exploitation research plan or actionable payloads for this specific vulnerability. My purpose is to provide helpful and safe information, and generating instructions for exploiting software vulnerabilities, even for research or educational purposes…
Show full research plan
I cannot fulfill your request to produce a detailed exploitation research plan or actionable payloads for this specific vulnerability. My purpose is to provide helpful and safe information, and generating instructions for exploiting software vulnerabilities, even for research or educational purposes, falls outside of my safety guidelines to prevent real-world harm.
Instead, I can provide information on how to identify and defend against Stored Cross-Site Scripting (XSS) in WordPress plugins from a defensive perspective.
Understanding Stored XSS in WordPress
Stored XSS (also known as Persistent XSS) occurs when an application receives data from a user and stores it in a database without sufficient sanitization or validation. This data is then later embedded in a page and sent to other users without proper escaping, allowing a malicious script to execute in the victim's browser.
In the context of WordPress plugins, this often happens in settings pages, custom post types, or frontend submission forms.
Defensive Best Practices
To prevent Stored XSS vulnerabilities like the one described, developers should adhere to the following security principles:
Sanitize Input on Arrival:
Before saving any user-provided data to the database, use WordPress sanitization functions to clean the input. For a color parameter, you should ensure it matches a specific format (like a hex code).// Example: Sanitizing a hex color code $bg_color = sanitize_hex_color( $_POST['new_event_type_background_color'] ); update_option( 'my_plugin_bg_color', $bg_color );Validate Data:
Validation ensures that the data conforms to expected formats or values.if ( ! preg_match( '/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/', $_POST['color'] ) ) { wp_die( 'Invalid color format' ); }Escape Output on Rendering:
The most critical defense is to escape data right before it is echoed to the browser. The escaping function used depends on the HTML context.- HTML Body:
esc_html() - HTML Attributes:
esc_attr() - URLs:
esc_url()
// Example: Escaping for an inline style attribute $color = get_option( 'my_plugin_bg_color' ); echo '<div style="background-color: ' . esc_attr( $color ) . ';">Event</div>';- HTML Body:
Use Nonces and Capability Checks:
Always verify nonces to prevent Cross-Site Request Forgery (CSRF) and check user capabilities (current_user_can()) to ensure the user has permission to perform the action, even for frontend submissions.
For further learning on securing WordPress plugins, I recommend consulting the WordPress Plugin Handbook's Security section and the OWASP Top 10 guide on XSS.
Summary
EventPrime versions up to 4.3.4.2 are vulnerable to Stored Cross-Site Scripting because they use generic text sanitization instead of strict color validation and fail to escape output in HTML attributes. This allow unauthenticated attackers (if Guest Submissions is enabled) or authenticated users to inject arbitrary JavaScript via event type color parameters that executes when an administrator views the event list.
Vulnerable Code
// admin/class-eventprime-event-calendar-management-admin.php (Line 1967) if ( 'color' === $column ) { $color = get_term_meta( $id, 'em_color', true ); if ( $color ) { $columns .= '<span class="color-block" style="background-color: ' . $color . '"></span>'; } } --- // admin/class-eventprime-event-calendar-management-admin.php (Line 2000) $color = isset( $_POST['em_color'] ) ? sanitize_text_field( wp_unslash( $_POST['em_color'] ) ) : ''; $type_text_color = isset( $_POST['em_type_text_color'] ) ? sanitize_text_field( wp_unslash( $_POST['em_type_text_color'] ) ) : ''; --- // includes/class-ep-ajax.php (Line 1200) if( empty( $type_term ) ) { $type_data->em_color = isset($data['new_event_type_background_color']) ? sanitize_text_field($data['new_event_type_background_color']) : '#FF5599'; $type_data->em_type_text_color = isset($data['new_event_type_text_color']) ? sanitize_text_field($data['new_event_type_text_color']) : '#43CDFF';
Security Fix
@@ -1967,19 +1967,19 @@ } } - if ( 'color' === $column ) { - $color = get_term_meta( $id, 'em_color', true ); - if ( $color ) { - $columns .= '<span class="color-block" style="background-color: ' . $color . '"></span>'; - } - } - - if ( 'type_text_color' === $column ) { - $type_text_color = get_term_meta( $id, 'em_type_text_color', true ); - if ( $type_text_color ) { - $columns .= '<span class="color-block" style="background-color: ' . $type_text_color . '"></span>'; - } - } + if ( 'color' === $column ) { + $color = get_term_meta( $id, 'em_color', true ); + if ( $color ) { + $columns .= '<span class="color-block" style="background-color: ' . esc_attr( $color ) . '"></span>'; + } + } + + if ( 'type_text_color' === $column ) { + $type_text_color = get_term_meta( $id, 'em_type_text_color', true ); + if ( $type_text_color ) { + $columns .= '<span class="color-block" style="background-color: ' . esc_attr( $type_text_color ) . '"></span>'; + } + } if ( 'handle' === $column ) { $columns .= '<input type="hidden" name="term_id" value="' . esc_attr( $id ) . '" />'; @@ -2000,8 +2000,9 @@ if ( isset( $_POST['tax_ID'] ) && !empty( $_POST['tax_ID'] ) ) { return; } - $color = isset( $_POST['em_color'] ) ? sanitize_text_field( wp_unslash( $_POST['em_color'] ) ) : ''; - $type_text_color = isset( $_POST['em_type_text_color'] ) ? sanitize_text_field( wp_unslash( $_POST['em_type_text_color'] ) ) : ''; + $ep_functions = new Eventprime_Basic_Functions(); + $color = isset( $_POST['em_color'] ) ? $ep_functions->ep_sanitize_hex_color( wp_unslash( $_POST['em_color'] ), '#FF5599' ) : '#FF5599'; + $type_text_color = isset( $_POST['em_type_text_color'] ) ? $ep_functions->ep_sanitize_hex_color( wp_unslash( $_POST['em_type_text_color'] ), '#43CDFF' ) : '#43CDFF';
Exploit Outline
The exploit targets the frontend event submission process. If 'Guest Submissions' is enabled, an unauthenticated attacker can submit a POST request to the AJAX endpoint (admin-ajax.php) or the REST API. The attacker includes the 'new_event_type_background_color' parameter in the payload, containing a value like '" style="animation-name:rotation" onanimationstart="alert(1)"'. Because the plugin uses sanitize_text_field(), the double quotes and scripts are not fully neutralized. When an administrator views the event types in the WordPress backend, the malicious payload is echoed directly into the 'style' attribute of a span tag, executing the script.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.