NotificationX <= 3.2.0 - Unauthenticated DOM-Based Cross-Site Scripting via 'nx-preview'
Description
The NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar plugin for WordPress is vulnerable to DOM-Based Cross-Site Scripting via the 'nx-preview' POST parameter in all versions up to, and including, 3.2.0. This is due to insufficient input sanitization and output escaping when processing preview data. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute when a user visits a malicious page that auto-submits a form to the vulnerable site.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=3.2.0Source Code
WordPress.org SVNThis exploitation research plan targets **CVE-2025-15380**, a DOM-based Cross-Site Scripting (XSS) vulnerability in the **NotificationX** plugin. The vulnerability exists because the plugin processes a `POST` parameter named `nx-preview` and reflects it into the page context without adequate sanitiz…
Show full research plan
This exploitation research plan targets CVE-2025-15380, a DOM-based Cross-Site Scripting (XSS) vulnerability in the NotificationX plugin. The vulnerability exists because the plugin processes a POST parameter named nx-preview and reflects it into the page context without adequate sanitization, which is subsequently executed by the plugin's frontend JavaScript.
1. Vulnerability Summary
- Vulnerability: Unauthenticated DOM-Based XSS.
- Vulnerable Parameter:
nx-preview(POST). - Component: Notification Preview Engine.
- Reason: The plugin allows users to "preview" notifications by sending their configuration via a
POSTrequest. The plugin reflects this configuration into a global JavaScript variable or a data attribute on the frontend. The plugin's client-side scripts then use this data to render a notification using dangerous DOM sinks (like.innerHTMLor jQuery's.html()) without escaping the content.
2. Attack Vector Analysis
- Endpoint: Any frontend page (e.g., the homepage
/) or pages where NotificationX scripts are loaded. - HTTP Method:
POST. - Authentication: None required (Unauthenticated).
- Preconditions:
- The plugin must be active.
- An attacker must obtain a valid nonce (accessible to unauthenticated users) to pass the
check_ajax_refererorwp_verify_noncecheck usually associated with preview functionality.
- Payload Delivery: Since it requires a
POSTrequest, the typical delivery is via a malicious site that auto-submits an external form to the target WordPress site (Cross-Site Request Forgery as a delivery mechanism for XSS).
3. Code Flow (Inferred)
- Entry Point: The plugin registers a handler on the
initorwp_loadedhook that checks for the existence of$_POST['nx-preview']. - Processing:
- The handler verifies a nonce (e.g.,
nx-preview). - The content of
$_POST['nx-preview'](expected to be a JSON string) is captured.
- The handler verifies a nonce (e.g.,
- Reflected Sink (PHP): The handler echoes the raw or partially sanitized JSON into the HTML response, likely inside a
<script>tag:var notificationx_preview_data = {"title": "...[PAYLOAD]..." }; - Execution Sink (JS): The plugin's frontend script (e.g.,
notificationx-public.js) readsnotificationx_preview_data. It iterates through the object and renders the notification. It likely uses a sink such as:jQuery('.nx-title').html(previewData.title);
4. Nonce Acquisition Strategy
NotificationX exposes nonces for its frontend functionality through wp_localize_script.
- Identify Shortcode: The plugin's scripts are typically enqueued when a notification is active or when the
[notificationx]shortcode is present. - Create Test Page:
wp post create --post_type=page --post_title="XSS Test" --post_status=publish --post_content='[notificationx]' - Extract Nonce:
Navigate to the newly created page and usebrowser_evalto find the nonce in the localized object.- Variable Name:
window.notificationx_ajax(inferred from common NotificationX patterns). - Nonce Key:
nx_preview_nonceornonce. - Extraction Command:
browser_eval("window.notificationx_ajax?.nx_preview_nonce")
- Variable Name:
5. Exploitation Strategy
Step 1: Discover the Nonce
Navigate to the homepage or the test page and extract the required nonce.
Step 2: Construct the Payload
The nx-preview parameter expects a JSON object representing a notification.
Payload:
{
"type": "sales",
"content": "<img src=x onerror=alert(document.domain)>",
"template_id": 1
}
Step 3: Execute the POST Request
Use the http_request tool to simulate the auto-submitting form.
- URL:
https://<target-site>/ - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded
- Body:
action=nx_preview_action&nx_preview_nonce=[NONCE]&nx-preview={"type":"sales","content":"<img src=x onerror=alert(1)>"}
(Note: The exact 'action' parameter may vary; it is often required for the init hook to route the request properly if it uses admin-ajax logic.)
6. Test Data Setup
- Plugin Installation: Ensure
notificationxversion 3.2.0 or lower is installed. - Active Notification: Create at least one "Sales" notification via the WordPress admin to ensure frontend scripts are initialized correctly.
# (Assuming WP-CLI support for the plugin) wp notificationx create --type=sales --title="Test" - Public Page: Ensure a page exists with the
[notificationx]shortcode to leak the nonce.
7. Expected Results
- The HTTP response should contain the JSON payload reflected within a
<script>block or a hidden input. - Upon rendering the page, the browser's JavaScript will process the
nx-previewJSON. - The malicious
<img>tag in thecontentfield will be injected into the DOM via a method like.html(). - The
onerrorevent will trigger, executingalert(1).
8. Verification Steps
- Manual Inspection: Use
http_requestto verify the payload is present in the response body.# Search for the reflected payload in the HTML response grep "onerror=alert" response.html - Automated Execution: Use
browser_navigateto the URL with the POST parameters (or use a local HTML file that auto-submits to the target) and check for a JavaScript dialog or a specific console log.
9. Alternative Approaches
- Base64 Encoding: Some versions of NotificationX expect the
nx-previewparameter to be Base64 encoded. If raw JSON fails, try:nx-preview=eyJ0eXBlIjoic2FsZXMiLCJjb250ZW50IjoiPGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPiJ9 - Direct Parameter Injection: Check if the plugin accepts the data via
$_GET['nx-preview']as well, though the description specifically highlights POST. - Different Templates: NotificationX has various notification types (Sales, Review, Announcement). If "Sales" is sanitized, "Announcement" or "Custom" might not be. Test the
nx-previewJSON with differenttypekeys.
Summary
The NotificationX plugin for WordPress is vulnerable to unauthenticated DOM-based Cross-Site Scripting (XSS) via the 'nx-preview' POST parameter in versions up to 3.2.0. The vulnerability is caused by insufficient input sanitization when processing notification preview data, which is then reflected into the page and rendered using unsafe JavaScript sinks. An attacker can exploit this by tricking a victim into visiting a page that auto-submits a malicious POST request, executing arbitrary scripts in their browser context.
Vulnerable Code
/* Inferred from client-side sink logic in scripts like notificationx-public.js */ jQuery('.nx-title').html(previewData.title); --- /* Inferred from server-side reflection of the nx-preview POST parameter */ var notificationx_preview_data = {"title": "...[PAYLOAD]..." };
Exploit Outline
1. Access the target WordPress site's frontend and extract a valid 'nx_preview_nonce' from the 'window.notificationx_ajax' localized script object. 2. Construct a malicious JSON payload representing a notification configuration (e.g., {"type":"sales","content":"<img src=x onerror=alert(1)>"}). 3. Craft a POST request to any page on the site where NotificationX scripts are loaded, including the parameters 'action=nx_preview_action', 'nx_preview_nonce', and the malicious 'nx-preview' JSON (which may need to be Base64 encoded depending on the specific version). 4. Use a CSRF-style auto-submitting form on an attacker-controlled page to force a victim's browser to send the POST request. 5. When the page renders, the plugin's JavaScript will read the reflected payload and inject it into the DOM using an unsafe sink like jQuery's .html(), triggering the execution of the arbitrary script.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.