Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-64638 — Proof-of-concept exploit for CVE-2026-64638: reflected XSS in WordPress login chained with DOM clobbering to achieve admin account takeover and remote code execution. | Kitploit
Tools/GitHubGitHub/dungsocool/cve-2026-64638
Phishing ToolsVulnerability AnalysisCode AnalysisExploitationWeb Application ExploitationWeb SecurityPayload Development
GitHubdungsocool/cve-2026-64638

CVE-2026-64638

Proof-of-concept exploit for CVE-2026-64638: reflected XSS in WordPress login chained with DOM clobbering to achieve admin account takeover and remote code execution.

View Repository
211 month agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-64638

Reflected XSS on Login Screen Leading to PHP Code Execution — WordPress Core

Software: WordPress Core ≤ 7.0.2 (all versions prior to 7.0.3)

CVSS: 8.9 (High)

CWE: CWE-79 — Improper Neutralization of Input During Web Page Generation

Authentication Required: None (Pre-Auth)

User Interaction: Active (admin needs to click 1 link)

Impact: XSS → Account Takeover → Remote Code Execution


1. What is this vulnerability?

WordPress is the most popular content management system in the world, accounting for over 40% of all websites on the internet. Every WordPress site has a login page at /wp-login.php — this is a public endpoint that anyone can access without authentication.

When a user enters an incorrect username, WordPress displays an error message containing the exact username that the user just typed: “The username X is not registered on this site.” The problem lies in the fact that the username value is placed directly into the HTML response without going through any escape function — an attacker simply needs to enter HTML/JavaScript instead of a real username, and the code will be executed in the browser.

This is a Reflected XSS flaw — the payload is contained in the request and reflected back identically by the server in the HTML. What makes it dangerous is that the flaw resides on the login page — a place frequently accessed by admins, where admin session cookies can be stolen.

The research team further discovered that this XSS can be chained with a DOM clobbering vulnerability in WordPress's emoji-loader, allowing JavaScript to be loaded from an external server. From there, an attacker can create a new admin account → install a plugin containing a webshell → execute PHP code on the server. This exploit chain is referred to as XSS2Shell.

AttributeValue
CVE IDCVE-2026-64638
CVSS Score8.9 (High)
SoftwareWordPress Core ≤ 7.0.2
AuthenticationNone required (Pre-Auth)
User InteractionRequires 1 click (admin clicks link)
Attack ComplexityHigh
PatchedWordPress 7.0.3 (08/06/2026)
Reporterpwn.ai team via HackerOne
HackerOne Report#3877102

2. Terminology Explanation

DOM Clobbering and emoji-loader

WordPress loads emoji support on every page (including the login page) via the file emoji-loader.js. This script reads configuration from an element with id="wp-emoji-settings":

// Before patch (vulnerable)
const settings = JSON.parse(
    document.getElementById('wp-emoji-settings').textContent
);

document.getElementById() returns the first element in the DOM with a matching id. If an attacker injects a <div id="wp-emoji-settings"> before the original script tag, getElementById will read the attacker's content instead of the real configuration. This technique is called DOM clobbering — overwriting JavaScript behavior by injecting HTML elements.

The emoji configuration contains a URL to load a JavaScript file (concatemoji). The attacker controls this URL → loads a JS file from an external server → executes arbitrary code within the browser context.

From XSS to RCE on WordPress

Once JavaScript execution within the admin context is achieved, the attacker has full WordPress admin privileges:

  1. Create a new admin account — call /wp-admin/user-new.php with the admin session
  2. Install a plugin containing PHP code — upload a plugin via /wp-admin/plugin-install.php
  3. Modify a theme file — insert a PHP backdoor via the Theme Editor

Any of the 3 methods above allows execution of PHP code on the server — meaning RCE.

3. Source Code Analysis — Root Cause

Step 1: Locate the Sink — Where the username is placed into HTML

From the fix commit 0d6d42e on wordpress-develop, I identified 3 locations in the file wp-includes/user.php where the username/email is placed directly into the error message:

# View diff between vulnerable and patched versions
git diff 7.0.2..7.0.3 -- src/wp-includes/user.php

Location 1 — Line 189 (username does not exist):

Before :

// BEFORE (vulnerable):
sprintf(
    __( 'The username <strong>%s</strong> is not registered...' ),
    $username      // ← no escaping
)

image.png

After :

// fixed:
sprintf(
    __( 'The username <strong>%s</strong> is not registered...' ),
    esc_html( $username )    // ← escaped
)

Location 2 — Line 216 (wrong password):

Before :

image.png

// BEFORE:
'<strong>' . $username . '</strong>'    // ← no escaping

After :

// AFTER:
'<strong>' . esc_html( $username ) . '</strong>'

Location 3 — Line 299 (wrong password for email):

Before :

image.png

// BEFORE:
'<strong>' . $email . '</strong>'    // ← no escaping

After :

// AFTER:
'<strong>' . esc_html( $email ) . '</strong>'

Step 2: Trace Source — Where does the data come from?

Data flow from the POST request to the error message:

$_POST['log']                           ← user input from login form
    ↓
wp_signon() [user.php:51]
    $credentials['user_login'] = wp_unslash($_POST['log'])     ← only removes backslashes
    ↓
wp_authenticate($username, $password) [pluggable.php:689]
    $username = sanitize_user($username)     ← strips HTML tags, but has a bypass
    ↓
wp_authenticate_username_password() [user.php:153]
    get_user_by('login', $username)          ← user not found
    ↓
    sprintf('The username <strong>%s</strong>...', $username)   ← XSS!
    ↓
WP_Error → login_header() → wp_admin_notice()
    wp_kses_post(...)     ← filters HTML but allows <div>, <a>,  through
    ↓
HTML response → browser render → JavaScript execute

Step 3: Two Defense Layers, Weak Points, and Confirmation via Debugging

WordPress has 2 filtering layers before the username reaches the HTML:

Layer 1: sanitize_user() — Calls strip_tags() to remove HTML tags. However, PHP's strip_tags() has known limitations: non-standard tag formatting can bypass the filter.

Layer 2: wp_kses_post() — Allows a safe subset of HTML through, including <div>, <a>, `` with certain attributes (but strips event handlers like onerror, onload). Crucially: wp_kses_post allows <div id="wp-emoji-settings"> — precisely the element needed for DOM clobbering.

The pwn.ai team found a way to bypass both layers to inject a useful payload. Specific technical details have not been publicly released.

Debugging with Xdebug — Data Flow Confirmation

To visually confirm that the username goes straight into HTML without escaping, I used Xdebug + VS Code to place breakpoints at key points in the execution chain.

Step 1 — Input XSS payload into the login form:

Access http://localhost:8282/wp-login.php, enter the username as `` then click Log In. An alert popup appears — XSS works.

image.png

image.png

Step 2 — Breakpoint at user.php:184 — Where XSS occurs:

Download Tool