A WordPress Flaw: The Login Form Hands Over the Server
A WordPress vulnerability nicknamed XSS2Shell turns a failed login into PHP code running on the server. Tracked as CVE-2026-64638, the flaw scores 8.9 on the CVSS scale. It starts with a username typed into the public login form and ends, under the right conditions, with an attacker-supplied plugin unpacked in your installation. WordPress shipped the fix in version 7.0.3 on 6 August 2026, backporting it as far as the 4.7 branch. Public exploit code appeared within days.
How the XSS2Shell Chain Works
The entry point is the login error message. Submit a username that does not exist and WordPress echoes it back to you on the page. That reflection is supposed to be inert, and two separate sanitizers stand in the way. The bypass found by the team at pwn.ai exploits a disagreement between them: strip_tags() does not treat a tag preceded by whitespace as a tag, so a payload shaped like < area id=ajaxurl> passes through untouched, while wp_kses_post() later reads the same string as valid HTML and renders it as a real element in the page.
What that element does is the clever part. It is not a script. It is a named DOM node that collides with a JavaScript variable WordPress leaves undefined on that screen, a technique called DOM clobbering. A core admin script reaches for ajaxurl, finds the attacker's element instead of nothing, and aims a request wherever the attacker pointed it. From there the chain runs through the site's own trusted code: a REST endpoint with JSONP support executes the attacker's JavaScript in the site's own origin, a cross-window method-execution trick reaches into a logged-in administrator's session to approve an Application Password, and that credential grants authenticated REST access.
The last step needs no exotic bug at all. The stolen Application Password carries administrator privileges, so the attacker simply uses the API to upload a plugin: a ZIP archive with PHP inside. On a single-site install an administrator also has unfiltered HTML rights by default, which is what makes the intermediate step of publishing a page full of JavaScript possible in the first place. At that point the code is not in the browser any more. It is executing with the privileges of the PHP worker, next to the database credentials.
What an Attacker Actually Needs
This is where the headline and the reality separate. The cross-site scripting half genuinely requires no account and no password, which is what makes the bug pre-authentication. The remote code execution half does not fire on its own. An administrator has to be signed in to the target site and has to open a link the attacker controls. No prompt appears, no confirmation is requested, and the victim sees nothing unusual, but the visit has to happen.
In practice that is a low bar. Site administrators click links in support tickets, contact forms, comment notifications and vendor emails all day, frequently in the same browser session where their dashboard is open. Treating "requires user interaction" as a comfort is how a chain like this gets left unpatched for a month.
Which Versions Are Affected
Every WordPress release from 4.7 up to and including 7.0.2 is vulnerable. That branch shipped in December 2016, which is why the affected range covers essentially every installation still receiving updates. WordPress released fixes across the whole supported tree on the same day, from 7.0.3 down through 6.9.6, 6.8.7 and onwards to 4.7.34. Anything on 4.6 or earlier gets no security updates at all and should be treated as permanently exposed.
XSS2Shell was one of twelve issues closed in that release. The others include stored cross-site scripting in the Post Date, Post Content, emoji settings and Quick Edit paths, an information disclosure bug exposing comments on password-protected posts, a bypass of the email confirmation flow, a CSS injection through the safe-attribute filter, a privilege escalation on multisite networks with open registration, a server-side request forgery in URL validation that reached link-local ranges, and an enumeration of post slugs. Even without the headline chain, that list is a reason to update today.
What to Do Now
- Update immediately: move to 7.0.3, or to the patched release on your branch. Automatic background updates handle minor security releases by default, but confirm the version rather than assuming.
- Audit Application Passwords: open every administrator profile and revoke any credential you do not recognise. This is the artefact the chain leaves behind, and it survives a password reset.
- Review users, plugins and files: look for administrator accounts you did not create and for plugins that appeared without a corresponding entry in your own change history.
- Do not browse your own dashboard everywhere: keeping the admin session in a separate browser profile from the one used for email and support tickets removes the exact precondition this attack depends on.
- Restrict the login screen: the reflection lives on wp-login.php. Limiting who can reach it, whether by IP allowlist, HTTP authentication or a firewall rule, shrinks the surface for the next bug in the same file.
Why This Matters Beyond Site Owners
A compromised WordPress installation is rarely the attacker's goal. It is a delivery vehicle, and the traffic it serves is trusted precisely because the domain is legitimate. We have seen the same pattern when an advertising script started rewriting crypto wallet addresses on thousands of ordinary websites, and the underlying idea is the same one behind browser-level attacks that ride an authenticated session the victim already has open. For a reader rather than an administrator, the practical defence is at the network layer: DNS filtering and blocklists stop the second-stage payload from loading even when the site delivering it is one you have visited for years. That is a plain argument for privacy tools that block at resolution time, and it is worth saying that no such tool patches your own server. Only the update does that.