Emergency server help: get in touch

WordPress CVE-2026-64638 Patch: Find and Update Every Vulnerable Site

WordPress CVE-2026-64638 (XSS2Shell): what is affected, which versions fix it per branch, and how hosts find and update every vulnerable site.

Published 8 min read

Short answer: CVE-2026-64638 (“XSS2Shell”) is a pre-authentication reflected XSS on the WordPress login screen that can be chained into PHP code execution if a logged-in administrator is tricked into following a link. It is fixed in WordPress 7.0.3 (6 August 2026) and in security releases for older branches such as 6.9.6 and 6.8.7. Hosts should scan every server for wp-includes/version.php, list sites below the fixed version for their branch, and update them with wp core update --minor run as each site’s owner, ideally straight to the newest release, since later releases fixed more issues.

Applies to WordPress 4.7 to 7.0.2, fixed in 7.0.3, 6.9.6, 6.8.7; tested on cPanel & WHM 11.138 and DirectAdmin 1.712

We ran the audit script, wp-toolkit --list and the wp-cli commands on our lab servers (AlmaLinux 9.8 with cPanel & WHM 11.138, and with DirectAdmin 1.712) on 6 October 2026. All lab sites were already on 7.1.2, so the “outdated” example uses a test folder. Vulnerability details were checked against the CVE record, the WordPress release post and independent advisories (linked below).

What CVE-2026-64638 is

ItemDetail
TypeReflected cross-site scripting (CWE-79) on the login screen, wp-login.php; no login needed to trigger it
SeverityCVSS 4.0 base score 8.9 (High) in the CVE record
AffectedWordPress before 7.0.3; the CVE record and WordPress say fixes were backported to branches back to 4.7
Fixed in7.0.3 (released 6 August 2026); backports include 6.9.6 and 6.8.7
ImpactUnder specific conditions involving social engineering and user interaction, the XSS can be chained into remote code execution
CVE published7 August 2026

Advisories differ on two points, so treat both cautiously:

  • Which old versions are really exploitable. The CVE record and the University of Toronto advisory treat every release from 4.7 to 7.0.2 as affected. Hadrian’s technical write-up says the payload only re-parses into HTML from 6.4 onwards. Patch everything regardless; the backports exist for a reason.
  • Exploitation status. Early advisories (7 August) reported no public exploit. Wiz’s vulnerability database now lists public proof-of-concept code and reports of exploitation in the wild. Assume it is being used.

The escalation path described by researchers needs an administrator who is logged in (or logs in) and opens an attacker’s page. That is why hosts with many small customer sites are exposed: plenty of site owners will click a convincing link.

Which version is “fixed” depends on the branch

Do not just flag every site below 7.0.3. A site on the 6.9 branch at 6.9.6 has the fix. A simple version comparison gets this wrong, so the audit below treats patched older branches separately:

BranchFirst fixed releaseNotes
7.07.0.3Upgrade to the latest 7.0.x or to 7.1.x
6.96.9.6Named by Wiz and the University of Toronto advisory
6.86.8.7Named by Wiz and the University of Toronto advisory
Older (down to 4.7)Branch security releaseCheck the WordPress release archive for that branch’s number
4.6 and olderNo fixEnd of life; upgrade or take offline

WordPress kept shipping security fixes after 7.0.3: 7.0.4 (12 August 2026) contained a security fix, 7.1.1 (17 September) eleven, and 7.1.2 (22 September) a fix for a critical vulnerability. Use 7.0.3 as the floor for this CVE, but update to the current release where you can.

Step 1: find every WordPress install on the server

Panel tools only see sites they know about. Customers also unpack WordPress by hand into subfolders, staging copies and old directories. Search the disk instead. Our wordpress-version-audit.sh script reads every wp-includes/version.php, maps the folder to a domain on cPanel and DirectAdmin, and flags old versions. On our cPanel lab:

./wordpress-version-audit.sh --branch-fix 6.9.6,6.8.7
WordPress version audit - panel: cpanel - minimum: 7.0.3 - branch fixes: 6.9.6,6.8.7

DOMAIN             PATH                     VERSION  OWNER  STATUS
site1.example.com  /home/site1/public_html  7.1.2    site1  OK
site2.example.com  /home/site2/public_html  7.1.2    site2  OK
site3.example.com  /home/site3/public_html  7.1.2    site3  OK

Installs found: 3 - outdated (< 7.0.3): 0

Against a test folder with one unpatched 7.0.2 copy and one 6.9.6 copy, the same script flagged only the 7.0.2 install and exited with code 1:

DOMAIN  PATH                                                 VERSION  OWNER  STATUS
-       /root/srvs-lab/test-hostB/wp-fixture/old-site        7.0.2    root   OUTDATED
-       /root/srvs-lab/test-hostB/wp-fixture/patched-branch  6.9.6    root   BRANCH-FIXED

Installs found: 2 - outdated (< 7.0.3): 1

Without the script, a one-liner gives you the raw list:

find /home -path /home/virtfs -prune -o -name version.php -path "*/wp-includes/*" -print 2>/dev/null \
  | xargs grep -H "^\$wp_version"

cPanel WP Toolkit view

If WP Toolkit is installed, it lists the installs it manages with their versions. From our cPanel lab:

wp-toolkit --list
  ID  Installation Path  Owner ID    State  Hidden  Website URL          Name        Version
   1       /public_html         3  Working   false  http://site1.example.com  Lab site 1    7.1.2

Compare its count with the disk scan. Anything the scan finds that WP Toolkit does not is a site nobody is updating.

Step 2: find out why sites are behind

Minor and security releases normally install themselves. A site still on 7.0.2 weeks later usually has automatic updates turned off. Check the common constants in wp-config.php:

grep -HnE "WP_AUTO_UPDATE_CORE|AUTOMATIC_UPDATER_DISABLED|DISALLOW_FILE_MODS" \
  /home/*/public_html/wp-config.php /home/*/domains/*/public_html/wp-config.php 2>/dev/null

Other causes: files not writable by the PHP user, a broken cron (WordPress checks for updates on page loads or WP-Cron), or a management plugin that pinned the version. Fix the cause or the site will fall behind again on the next release.

Step 3: update every flagged site

Take a backup of files and database for each site before updating, or confirm last night’s backup is restorable. Updating core is low risk, but very old sites can break on a big jump.

Run wp-cli as the site owner, never as root, so file ownership stays correct. --minor updates within the site’s branch (7.0.2 to the latest 7.0.x, 6.9.x to the latest 6.9.x), which is the safest jump:

sudo -u bob -- wp core version --path=/home/bob/public_html
sudo -u bob -- wp core update --minor --path=/home/bob/public_html
sudo -u bob -- wp core update-db --path=/home/bob/public_html

On our cPanel lab, sudo -u USER -- wp failed with sudo: wp: command not found, because sudo’s restricted PATH did not include /usr/local/bin. Call the binary with its full path instead:

sudo -u bob -- /usr/local/bin/php /usr/local/bin/wp core version --path=/home/bob/public_html

To update everything the audit flagged, feed its CSV into a loop. Review the list first:

./wordpress-version-audit.sh --branch-fix 6.9.6,6.8.7 --only-outdated --csv > /root/wp-outdated.csv
cat /root/wp-outdated.csv
tail -n +2 /root/wp-outdated.csv | while IFS=, read -r domain path version owner status; do
  echo "== $domain ($path) $version"
  sudo -u "$owner" -- /usr/local/bin/php /usr/local/bin/wp core update --minor --path="$path" </dev/null
done

The simple read split assumes paths without commas, which is normal on hosting servers. With WP Toolkit, you can update from its interface instead; it shows the same list of installs.

Step 4: verify the update and look for misuse

sudo -u bob -- /usr/local/bin/php /usr/local/bin/wp core version --path=/home/bob/public_html
sudo -u bob -- /usr/local/bin/php /usr/local/bin/wp core verify-checksums --path=/home/bob/public_html
./wordpress-version-audit.sh --branch-fix 6.9.6,6.8.7 --only-outdated

verify-checksums compares core files with WordPress.org’s list. On our lab sites (7.1.2) it reported warnings for files under wp-includes/php-ai-client/ and returned an error, on a clean install. Read the file list before treating a failure as a compromise; unexpected PHP files in wp-admin or wp-includes are what matter.

Because the attack ends with an administrator’s session being abused, check flagged sites for signs of it:

  • New administrator accounts: wp user list --role=administrator.
  • New or unknown plugins, especially recently uploaded ones: wp plugin list and the modification times in wp-content/plugins.
  • New application passwords, which researchers describe as part of the chain: wp user application-password list USER.
  • Your malware scanner’s results for the account.

Hardening steps the University of Toronto advisory recommends after patching: disable application passwords where nobody uses them, set DISALLOW_FILE_MODS on sites that do not need plugin installs from the dashboard, and keep the number of administrator accounts small.

Common problems

  • Error: Another update is currently in progress. A previous update left a lock. Wait 15 minutes or remove the core_updater.lock option with wp option delete core_updater.lock.
  • Update fails with permission errors: files are owned by root or another user. Fix ownership to the site owner first.
  • Site on 4.6 or older: no fix exists. Plan a full upgrade with the owner, or take it offline.
  • Updated site still flagged: a second copy (staging, backup folder) exists. Remove it or update it too.

Official documentation: WordPress 7.0.3 release · CVE-2026-64638 record (MITRE API) · Wiz: CVE-2026-64638 · University of Toronto: XSS2Shell advisory

Related: WP Toolkit CVE-2026-87900: what is affected and how to patch to 6.11.3 · Using WP Toolkit Security Risk scores, Smart Update and Vulnerable Components · Server hacked: incident response runbook for Linux and cPanel · DirectAdmin WordPress Manager and wp-cli: Site Control · cPanel PHP Version Audit

See also: Clean a Hacked WordPress Site on cPanel: Step-by-Step · WordPress Version Audit: Find Every WordPress Site and Its Version · Imunify360 False Positives: Find the Rule ID and Fix It

Frequently asked questions

Which WordPress version fixes CVE-2026-64638?

WordPress 7.0.3, released 6 August 2026. Older branches got security releases too, including 6.9.6 and 6.8.7.

Is a site on WordPress 6.9.6 vulnerable?

No. 6.9.6 is the security release for the 6.9 branch and contains the fix. Flag only sites below the fixed release for their branch.

Can a WAF protect unpatched sites?

Some vendors shipped WAF rules, but one advisory says a WAF or Content Security Policy cannot reliably stop this attack. Patch core.

Does the attacker need a login?

No for the XSS. The escalation to code execution needs a logged-in administrator to be tricked into opening the attacker’s page.

Why are some sites not auto-updating?

Usually WP_AUTO_UPDATE_CORE or AUTOMATIC_UPDATER_DISABLED in wp-config.php, wrong file ownership, or a broken WP-Cron.

Maintenance record

This guide changes servers, data or security settings, so we re-check it against current versions on a fixed schedule. Take a backup or snapshot before you start.

Maintained by
srvScripts editorial team
Supported versions
WordPress 4.7 to 7.0.2, fixed in 7.0.3, 6.9.6, 6.8.7; tested on cPanel & WHM 11.138 and DirectAdmin 1.712
Last full review
Next review

Free website test

Is your website set up right?

Check SSL, security headers, redirects, robots.txt, sitemap, llms.txt and security.txt in one test. It takes about 30 seconds.