CVE-2026-1191

JavaScript Notifier <= 1.2.8 - Authenticated (Administrator+) Stored Cross-Site Scripting via Plugin Settings

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
4.4
CVSS Score
4.4
CVSS Score
medium
Severity
1.2.9
Patched in
11d
Time to patch

Description

The JavaScript Notifier plugin for WordPress is vulnerable to Stored Cross-Site Scripting via plugin settings in all versions up to, and including, 1.2.8. This is due to insufficient input sanitization and output escaping on user-supplied attributes in the `wp_footer` action. This makes it possible for authenticated attackers, with administrator-level access, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
High
Privileges Required
High
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.2.8
PublishedJanuary 23, 2026
Last updatedFebruary 3, 2026
Affected pluginjavascript-notifier
Research Plan
Unverified

This research plan outlines the steps to exploit a Stored Cross-Site Scripting (XSS) vulnerability in the **JavaScript Notifier** plugin for WordPress (versions <= 1.2.8). ## 1. Vulnerability Summary The **JavaScript Notifier** plugin fails to properly sanitize and escape settings saved by an admin…

Show full research plan

This research plan outlines the steps to exploit a Stored Cross-Site Scripting (XSS) vulnerability in the JavaScript Notifier plugin for WordPress (versions <= 1.2.8).

1. Vulnerability Summary

The JavaScript Notifier plugin fails to properly sanitize and escape settings saved by an administrator. These settings are subsequently retrieved and rendered directly into the site's footer via the wp_footer action hook. An attacker with administrator-level privileges can inject arbitrary JavaScript, which will execute in the context of any user (including other administrators) who visits the site's frontend.

2. Attack Vector Analysis

  • Vulnerable Endpoint: WordPress Admin Settings (/wp-admin/options.php).
  • Vulnerable Action: wp_footer (frontend rendering).
  • Vulnerable Parameters: The specific setting fields registered by the plugin (likely js_notifier_text or similar).
  • Preconditions:
    • Authenticated user with administrator privileges (required to access the settings page).
    • Plugin version <= 1.2.8 installed and active.

3. Code Flow (Inferred)

  1. Entry Point (Admin): The administrator navigates to the plugin's settings page, usually registered via add_options_page() in a function hooked to admin_menu.
  2. Storage: Settings are registered via register_setting(). When the form is submitted to options.php, WordPress calls update_option(). The plugin fails to provide a sanitize_callback during registration, or the callback is insufficient.
  3. Sink (Frontend): The plugin registers a function to the wp_footer hook:
    add_action('wp_footer', 'javascript_notifier_display');
    
  4. Rendering: Inside javascript_notifier_display(), the plugin retrieves the stored option:
    $options = get_option('javascript_notifier_settings');
    echo $options['notifier_text']; // VULNERABLE: No esc_html() or esc_attr()
    

4. Nonce Acquisition Strategy

To update the settings via options.php, a valid settings nonce and the option_page identifier are required.

  1. Identify the Page: Navigate to the JavaScript Notifier settings page (likely wp-admin/options-general.php?page=javascript-notifier).
  2. Identify the Option Group: Look for the hidden input field option_page.
  3. Extract Nonce:
    • Action: browser_navigate to the settings page.
    • Action: browser_eval to extract the nonce:
      ({
          nonce: document.querySelector('input[name="_wpnonce"]')?.value,
          option_page: document.querySelector('input[name="option_page"]')?.value
      })
      

5. Exploitation Strategy

Step 1: Discover Setting Parameters

Since source files are not provided, we first need to identify the exact key used in the options.php request.

  1. Navigate to the settings page.
  2. Inspect the name attributes of the input fields (e.g., javascript_notifier_options[message]).

Step 2: Inject Payload

Submit a POST request to options.php as an administrator.

  • URL: https://<target>/wp-admin/options.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body (Example):
    option_page=javascript_notifier_settings&
    _wpnonce=<EXTRACTED_NONCE>&
    action=update&
    javascript_notifier_options[message]=<script>alert(document.domain)</script>
    

Step 3: Trigger Execution

Navigate to any frontend page of the WordPress site. The wp_footer hook executes on every frontend page load.

6. Test Data Setup

  1. Install Plugin: Ensure javascript-notifier version 1.2.8 is installed.
  2. User: Create an administrator user.
  3. Plugin Config: Navigate to the settings page once to ensure the option is initialized in the database.

7. Expected Results

  • The options.php request should return a 302 Redirect back to the settings page with settings-updated=true.
  • Viewing the frontend source code (near the closing </body> tag) should show the raw payload: <script>alert(document.domain)</script>.
  • A JavaScript alert box should appear when visiting the site's homepage.

8. Verification Steps

After the exploit, use wp-cli to verify the state of the database:

# Check the stored option value
wp option get javascript_notifier_options

Verify that the message (or relevant key) contains the unescaped <script> tag.

9. Alternative Approaches

If the plugin uses a custom AJAX handler instead of the Options API:

  1. Search for wp_ajax_ hooks in the plugin code: grep -r "wp_ajax_" ..
  2. Locate the saving function and check for nonce verification: check_ajax_referer('...', '...').
  3. Construct an AJAX POST request to wp-admin/admin-ajax.php.

If the XSS is rendered inside an existing <script> block rather than directly in HTML:

  1. Payload: ";alert(document.domain);//
  2. Check for wp_add_inline_script or wp_localize_script calls that might be the sink.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.