Custom New User Notification <= 1.2.0 - Authenticated (Administrator+) Stored Cross-Site Scripting via 'User Mail Subject' Setting
Description
The Custom New User Notification plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the plugin's admin settings in all versions up to, and including, 1.2.0. This is due to insufficient input sanitization and output escaping on multiple settings fields including 'User Mail Subject', 'User From Name', 'User From Email', 'Admin Mail Subject', 'Admin From Name', and 'Admin From Email'. The settings are registered via register_setting() without sanitize callbacks, and the values retrieved via get_option() are echoed directly into HTML input value attributes without esc_attr(). This makes it possible for authenticated attackers, with Administrator-level access and above, to inject arbitrary web scripts in the plugin settings page that will execute whenever a user accesses that page. This could be used in multi-site installations where administrators of subsites could target super administrators.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.2.0This research plan targets a Stored Cross-Site Scripting (XSS) vulnerability in the "Custom New User Notification" plugin (<= 1.2.0). --- ### 1. Vulnerability Summary The **Custom New User Notification** plugin fails to sanitize and escape several configuration settings. These settings (e.g., `Use…
Show full research plan
This research plan targets a Stored Cross-Site Scripting (XSS) vulnerability in the "Custom New User Notification" plugin (<= 1.2.0).
1. Vulnerability Summary
The Custom New User Notification plugin fails to sanitize and escape several configuration settings. These settings (e.g., User Mail Subject, User From Name) are registered via register_setting() without a sanitize_callback and later rendered in the admin settings dashboard via get_option() directly inside HTML input value attributes without using esc_attr(). This allows an authenticated administrator (or a sub-site administrator in a Multi-site environment) to inject a payload that breaks out of the HTML attribute and executes arbitrary JavaScript in the context of any user (typically a Super Admin or Admin) visiting the settings page.
2. Attack Vector Analysis
- Vulnerable Endpoint:
wp-admin/options.php(Standard WordPress settings handler). - Vulnerable Page: The plugin's settings page, typically located at
wp-admin/options-general.php?page=custom-new-user-notification(inferred slug). - HTTP Parameter:
user_mail_subject,user_from_name,user_from_email,admin_mail_subject,admin_from_name, oradmin_from_email. - Authentication Required: Administrator (or Sub-site Admin in Multi-site).
- Preconditions: The plugin must be active.
3. Code Flow (Inferred from Patch Description)
- Registration: During
admin_init, the plugin callsregister_setting( 'cnun_options_group', 'user_mail_subject' )(group name inferred). It fails to provide a third argument with asanitize_callbacklikesanitize_text_field. - Storage: When an admin submits the settings form,
options.phpreceives the raw payload and updates the option in thewp_optionstable viaupdate_option(). - Output (The Sink): In the admin menu callback function (registered via
add_options_page):- The plugin retrieves the value:
$subject = get_option('user_mail_subject'); - The plugin echoes the value into a form:
echo '<input type="text" name="user_mail_subject" value="' . $subject . '" />'; - Because
$subjectcontains"><script>alert(1)</script>, the HTML becomes:<input ... value=""><script>alert(1)</script>" />.
- The plugin retrieves the value:
4. Nonce Acquisition Strategy
Since this exploit targets the standard WordPress Settings API, it requires a nonce generated for the specific settings group.
- Identify the Page: Navigate to the plugin settings page.
- Navigate and Inspect: Use
browser_navigateto go toURL_BASE + "/wp-admin/options-general.php?page=custom-new-user-notification". - Extract Nonce and Group: Use
browser_evalto extract the_wpnonceand theoption_pagevalues from the hidden inputs.// Example browser_eval logic { "option_page": document.querySelector('input[name="option_page"]')?.value, "nonce": document.querySelector('input[name="_wpnonce"]')?.value } - Confirm Identifier: Confirm if the
option_pagematchescnun_options_groupor similar.
5. Exploitation Strategy
Payload: "><script>alert(window.origin)</script>
Step 1: Authentication
Log in to the WordPress instance as an Administrator using the provided credentials.
Step 2: Information Gathering
Navigate to the settings page to confirm the exact parameter names and the nonce.
- URL:
/wp-admin/options-general.php?page=custom-new-user-notification
Step 3: Execution (HTTP Request)
Send a POST request to options.php to store the payload.
- Method:
POST - URL:
/wp-admin/options.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
option_page=[EXTRACTED_OPTION_PAGE]& action=update& _wpnonce=[EXTRACTED_NONCE]& user_mail_subject="><script>alert(window.origin)</script>& submit=Save+Changes
Step 4: Triggering the XSS
Navigate back to the settings page: /wp-admin/options-general.php?page=custom-new-user-notification.
6. Test Data Setup
- Active Plugin: Ensure
custom-new-user-notificationis installed and activated. - Admin User: Create or use an existing Administrator account.
- Initial State: Ensure the settings fields are currently empty or contain default values.
7. Expected Results
- The
options.phprequest should return a302 Redirectback to the settings page withsettings-updated=true. - Upon navigating to the settings page, the browser should execute the JavaScript
alert(window.origin). - The HTML source of the page should show the payload breaking out of the
valueattribute:<input ... value=""><script>alert(window.origin)</script>" />
8. Verification Steps
- Check DB via WP-CLI:
Confirm the output matches the injected payload.wp option get user_mail_subject - DOM Inspection: Use
browser_evalto check if the script tag exists in the DOM after the settings page loads.document.getElementsByTagName('script').length // And search for the alert content
9. Alternative Approaches
- Other Sinks: If
user_mail_subjectis sanitized (unlikely given the report), repeat the process foruser_from_name,admin_mail_subject, etc. - Attribute-Based Payloads: If
<script>tags are blocked by a WAF but the attribute breakout is still possible, use an event handler:" onmouseover="alert(1) - Multi-site Context: If testing in a Multi-site environment, perform the update as a Blog Admin and verify the trigger as a Super Admin.
Summary
The Custom New User Notification plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) due to insufficient input sanitization and output escaping on multiple settings fields. Authenticated administrators can inject arbitrary web scripts into fields like 'User Mail Subject', which will execute whenever an administrator (such as a Super Admin in multi-site) accesses the plugin's settings page.
Vulnerable Code
// Registration of settings without sanitization callbacks during admin_init register_setting( 'cnun_options_group', 'user_mail_subject' ); register_setting( 'cnun_options_group', 'user_from_name' ); register_setting( 'cnun_options_group', 'user_from_email' ); --- // Rendering the settings page without escaping output in value attributes $user_mail_subject = get_option('user_mail_subject'); echo '<input type="text" name="user_mail_subject" value="' . $user_mail_subject . '" />';
Security Fix
@@ -10,12 +10,12 @@ function cnun_register_settings() { - register_setting( 'cnun_options_group', 'user_mail_subject' ); - register_setting( 'cnun_options_group', 'user_from_name' ); - register_setting( 'cnun_options_group', 'user_from_email' ); + register_setting( 'cnun_options_group', 'user_mail_subject', 'sanitize_text_field' ); + register_setting( 'cnun_options_group', 'user_from_name', 'sanitize_text_field' ); + register_setting( 'cnun_options_group', 'user_from_email', 'sanitize_email' ); } function cnun_settings_page() { - $user_mail_subject = get_option('user_mail_subject'); + $user_mail_subject = (string) get_option('user_mail_subject'); - echo '<input type="text" name="user_mail_subject" value="' . $user_mail_subject . '" />'; + echo '<input type="text" name="user_mail_subject" value="' . esc_attr( $user_mail_subject ) . '" />'; }
Exploit Outline
1. Authenticate to the WordPress dashboard as an Administrator. 2. Navigate to the plugin's settings page (typically under Settings > Custom New User Notification) and inspect the HTML source to identify the `option_page` value and the `_wpnonce` value generated by the Settings API. 3. Send a POST request to `/wp-admin/options.php` including the valid `_wpnonce`, the `option_page` identifier, and a malicious payload in the `user_mail_subject` parameter, such as: "><script>alert(document.domain)</script>. 4. Ensure the `action` parameter is set to `update`. 5. To trigger the vulnerability, navigate back to the plugin's settings page; the injected script will execute in the browser context of any user viewing the page.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.