Someone leaves a comment on your blog and silently owns your entire web server
CVE-2026-93485 is an unauthenticated stored cross-site scripting flaw in WordPress core's wpautop() paragraph-formatting function, affecting every version from 4.7 through 7.1. An anonymous visitor submits a comment containing a <blockquote cite="..."> tag with embedded newlines. The payload passes wp_kses() sanitization cleanly — nothing looks dangerous. But when the comment renders, the newlines trigger a cascade of misparses across wpautop() and wptexturize() that manufacture a valid JavaScript event handler (onfocus/autofocus) from what was inert markup. The XSS fires whenever *anyone* — visitor or admin — views the page. Researcher Rafie Muhammad of Awesome Motive published a complete Comment2Shell proof-of-concept on September 21 showing that when the payload fires in an admin session, injected JS fetches the plugin-upload form, extracts the nonce, POSTs a malicious ZIP, and achieves full server-side RCE without the plugin ever being activated. Fixed in WordPress 7.1.1 (Sept 17, 2026), backported to every supported branch down to 4.7.36.
The vendor rates this HIGH 7.1, but that score was built on CVSS impact values of C:L/I:L/A:L — scoring only the XSS itself, not the demonstrated RCE chain. Once an admin views the poisoned page, the attacker obtains web-server-level code execution: confidentiality, integrity, and availability impact are all effectively HIGH. With ~59 million WordPress sites visible on the internet (Censys, June 2026), only 14% running the latest patch, comments enabled by default, and the approval gate documented as bypassable, the real-world exploitability far exceeds what the 7.1 label conveys. The vendor severity understates the risk for any internet-facing WordPress site running default comment settings.
5 steps from start to impact.
Anonymous comment submission
/wp-comments-post.php endpoint on any post with comments enabled (the WordPress default). No authentication, CAPTCHA, or account is required. The comment body contains a <blockquote cite="a\nb"> payload that is structurally valid HTML and passes wp_kses() allowlist sanitization without modification.- Target WordPress site has comments enabled on at least one post
- Attacker can reach the site over HTTP/HTTPS
- Some enterprise sites disable comments entirely or require registration
- Anti-spam plugins (Akismet, reCAPTCHA) may block automated submission but do not inspect payload structure
- WAFs with stored-XSS detection rules may flag the blockquote pattern
<script> tag.Comment approval bypass
- Comment moderation is off (default in many configs) OR the approval gate is bypassed
- Sites with strict moderation workflows and human review will block the comment from rendering publicly
- Disqus or other third-party comment systems replace the native comment pipeline entirely
blockquote tags with cite attributes.Stored XSS fires in admin session
onfocus+autofocus event handler executes JavaScript in their authenticated session. Because this is stored XSS, the payload fires every time the page loads until the comment is removed. No additional user interaction (clicking, hovering) is required beyond viewing the page.- An admin or user with
upload_pluginscapability views the page containing the comment
- Content Security Policy (CSP) with
script-srcrestrictions blocks inline event handlers — but <5% of WordPress sites deploy CSP - Browser XSS filters (legacy X-XSS-Protection) are deprecated in modern browsers and do not stop stored XSS
Comment2Shell: XSS escalates to RCE
/wp-admin/plugin-install.php?tab=upload to retrieve the upload form and nonce, (2) constructs a ZIP file containing a PHP webshell in-memory, (3) POSTs it to /wp-admin/update.php?action=upload-plugin, and (4) accesses the uploaded file at /wp-content/plugins/[name]/[file].php to trigger execution. The entire chain completes in under 2 seconds without any user-visible indication. The attacker now has arbitrary code execution as the web server user (typically www-data or apache).- Admin session has
upload_pluginsandinstall_pluginscapabilities (default for Administrator role) - Plugin file uploads are not blocked by server configuration
- Hardened installs that define
DISALLOW_FILE_MODSinwp-config.phpblock plugin uploads entirely - Managed WordPress hosts (WP Engine, Pantheon, WordPress.com) restrict filesystem writes and plugin uploads via the admin UI
- File integrity monitoring (OSSEC, Wazat, Tripwire) will detect new files in
wp-content/plugins/
Post-exploitation: webshell and pivot
wp-config.php (database credentials), dump the WordPress database (user accounts, hashed passwords, PII), pivot to the database server, scan internal networks if the web server has internal connectivity, or install persistent backdoors. On shared hosting, this may enable lateral movement to other tenants.- Web server process has filesystem and network access (standard)
- Containerized or sandboxed WordPress deployments (Docker, Kubernetes pods) limit lateral movement
- Network segmentation between web tier and internal networks prevents pivot
- Database credentials may use least-privilege accounts limiting data access
The supporting signals.
| In-the-Wild Status | No confirmed exploitation as of 2026-09-24. Not listed in CISA KEV. However, full PoC was publicly disclosed on Sept 21 — the window for weaponization is open. |
|---|---|
| Proof-of-Concept | Public and functional. Rafie Muhammad published the complete Comment2Shell chain on Sept 21, 2026, demonstrating unauth XSS → admin session hijack → plugin upload → RCE. Reproduced on default WordPress installs. |
| EPSS | 0.00161 (94th percentile) — relatively high for a 6-day-old CVE. Expect this to climb sharply now that the PoC is public. |
| KEV Status | Not listed. No CISA KEV entry as of 2026-09-24. Given the public PoC and massive attack surface, KEV addition is plausible if exploitation is confirmed. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L (7.1) — Network-accessible, no privileges, low complexity, but requires user interaction (victim views page). Scope is Changed (XSS crosses origin). Impact rated Low across C/I/A, which *does not account* for the RCE escalation chain. |
| Affected Versions | WordPress 4.7 through 7.1 — every major release branch over the past ~9 years. The flaw has existed in wpautop() since at least WordPress 4.7 (Dec 2016). |
| Fixed Versions | 7.1.1, 7.0.5, 6.9.8, 6.8.9, 6.7.8, 6.6.8, 6.5.11, 6.4.11, 6.3.11, 6.2.12, 6.1.13, 6.0.15, 5.9.17, 5.8.16, 5.7.18, 5.6.20, 5.5.21, 5.4.22, 5.3.24, 5.2.27, 5.1.25, 5.0.28, 4.9.32, 4.8.31, 4.7.36. One-line fix in the wpautop() blockquote regex. |
| Exposure / Attack Surface | ~59 million WordPress sites visible on the internet (Censys, June 2026). Only 14% on latest patch. Comments are enabled by default on all posts. FOFA/Shodan fingerprinting for WordPress is trivial. |
| Disclosure Timeline | Sept 15, 2026: reported via Patchstack VDP. Sept 17: WordPress 7.1.1 released. Sept 18: CVE published. Sept 21: full PoC + technical writeup disclosed publicly. |
| Researcher | Rafie Muhammad (Awesome Motive Inc.), reported via Patchstack Vulnerability Disclosure Program. |
Why this verdict
- CVSS underscores actual impact: The vendor vector rates C/I/A as Low/Low/Low, scoring only the XSS. The publicly demonstrated Comment2Shell chain escalates to full RCE (C:H/I:H/A:H) with no additional attacker interaction once the admin views the page. Rescoring impact alone moves this from 7.1 to ~9.0.
- Default-config exploitable with zero authentication: Comments are enabled by default. The approval gate is bypassable on stock installs. No account, no credentials, no social engineering — just a POST to the comment endpoint. This is the lowest possible friction for a stored XSS.
- Public weaponizable PoC on a 59M-instance platform: The Comment2Shell chain was published 3 days after the patch. With 86% of WordPress sites unpatched (Censys) and trivial fingerprinting, mass exploitation is a matter of when, not if. EPSS is already at the 94th percentile and climbing.
- Role multiplier: WordPress is a web application, not canonical infrastructure (not IdP, DC, hypervisor, backup). Compromise yields site-level RCE and database access — serious, but blast radius is *per-site*, not domain/fleet/supply-chain scale. WordPress servers in enterprise DMZs could provide initial network access, but this requires hosting-specific conditions. The role does not trigger the CRITICAL floor.
- UI:R friction is real but minimal for stored XSS: The payload persists in the database and fires on every page load. On any actively maintained site, an admin will view the page within hours to days. This is not a reflected XSS that requires a phishing click — the trap is set and waits.
Why not higher?
WordPress is not a canonical high-value infrastructure component — it is a web application. Compromise of a WordPress site yields server-level RCE on the web tier, but does not inherently lead to domain takeover, fleet compromise, identity-plane breach, or supply-chain pivot. The blast radius is per-site, bounded by the hosting environment's segmentation. The UI:R prerequisite, while nearly guaranteed on active sites, is still a real friction point that separates this from a zero-click network worm. These factors prevent escalation to CRITICAL.
Why not lower?
The chain from anonymous comment to full server RCE is fully documented, publicly available, and works on default configurations. The affected platform has 59 million internet-facing instances with an 86% unpatched rate. The XSS is stored (not reflected), meaning it is persistent and fires without attacker re-engagement. Downgrading below HIGH would ignore the demonstrated RCE escalation path, the massive attack surface, and the near-certain triggering of the stored payload on any active site.
What to do — in priority order.
- Deploy WAF rules blocking the blockquote-newline pattern — Wordfence and Patchstack released detection rules on Sept 18. If you run a WAF (Cloudflare, Akamai, ModSecurity), add a rule to block comment submissions containing
<blockquotewithciteattributes containing\nor%0a. This is your fastest mitigation — deploy within the noisgate mitigation SLA of 30 days for HIGH, though given the public PoC, deploying within 72 hours is strongly recommended. - Disable comments on all posts and pages — Run
wp option update default_comment_status closedvia WP-CLI, or set Settings → Discussion → uncheck 'Allow people to submit comments on new posts' and bulk-close existing comments. This eliminates the attack vector entirely without patching. Apply fleet-wide immediately. - Set DISALLOW_FILE_MODS in wp-config.php — Add
define('DISALLOW_FILE_MODS', true);towp-config.php. This blocks the plugin-upload step of the Comment2Shell RCE chain, breaking the escalation from XSS to code execution even if the XSS fires. It does NOT fix the XSS itself. - Deploy Content Security Policy headers — Set
Content-Security-Policy: script-src 'self'(or tighter) on all WordPress front-end responses. This blocks inline event handlers like theonfocuspayload from executing, neutralizing the XSS. Test thoroughly — many WordPress themes and plugins rely on inline scripts and will break without'unsafe-inline'. - Patch to WordPress 7.1.1 or the corresponding backport for your branch — This is the definitive fix. The patch is a one-line regex change in
wpautop(). Apply within the noisgate remediation SLA of 180 days for HIGH. Given the public PoC and massive attack surface, prioritize patching within 30 days. Usewp core updatevia WP-CLI for fleet deployment. - Enable file integrity monitoring on wp-content/plugins/ — Deploy OSSEC, Wazara, Tripwire, or equivalent FIM to detect new PHP files in plugin directories. This does not prevent exploitation but catches the RCE payload landing and enables rapid incident response.
- Akismet / anti-spam plugins — these detect spam patterns (links, keywords, known spammer IPs) but do not inspect HTML structure for XSS payloads. The malicious comment contains no spam indicators.
- X-XSS-Protection header — deprecated in all modern browsers (Chrome removed it in 2019). It only ever targeted reflected XSS, not stored XSS. Setting this header provides zero protection.
- Requiring user registration for comments — reduces anonymous attack surface but does not prevent exploitation. An attacker can register an account (if registration is open) and submit the same payload. The XSS is in the rendering pipeline, not the authentication layer.
- Rate limiting comment submissions — the attack requires only a single comment. Rate limiting does not help.
Crowdsourced verification payload.
Run this script on each WordPress host as any user with read access to the WordPress installation directory. Usage: bash check_cve_2026_93485.sh /var/www/html (pass the WordPress root directory as the first argument). No root privileges required.
#!/usr/bin/env bash
# CVE-2026-93485 — WordPress Core Stored XSS in wpautop()
# Checks WordPress version against patched releases.
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
WP_ROOT="${1:-/var/www/html}"
VERSION_FILE="$WP_ROOT/wp-includes/version.php"
if [[ ! -f "$VERSION_FILE" ]]; then
echo "UNKNOWN — Cannot find $VERSION_FILE. Is this a WordPress installation?"
exit 2
fi
# Extract the $wp_version variable from version.php
WP_VERSION=$(grep -oP "\\\$wp_version\\s*=\\s*'\\K[^']+" "$VERSION_FILE" 2>/dev/null)
if [[ -z "$WP_VERSION" ]]; then
echo "UNKNOWN — Could not parse WordPress version from $VERSION_FILE"
exit 2
fi
echo "Detected WordPress version: $WP_VERSION"
# Patched versions per branch (first patched release)
declare -A PATCHED_VERSIONS=(
["7.1"]=1 ["7.0"]=5 ["6.9"]=8 ["6.8"]=9 ["6.7"]=8
["6.6"]=8 ["6.5"]=11 ["6.4"]=11 ["6.3"]=11 ["6.2"]=12
["6.1"]=13 ["6.0"]=15 ["5.9"]=17 ["5.8"]=16 ["5.7"]=18
["5.6"]=20 ["5.5"]=21 ["5.4"]=22 ["5.3"]=24 ["5.2"]=27
["5.1"]=25 ["5.0"]=28 ["4.9"]=32 ["4.8"]=31 ["4.7"]=36
)
# Parse major.minor and patch from version string
if [[ "$WP_VERSION" =~ ^([0-9]+\.[0-9]+)\.([0-9]+)$ ]]; then
BRANCH="${BASH_REMATCH[1]}"
PATCH="${BASH_REMATCH[2]}"
elif [[ "$WP_VERSION" =~ ^([0-9]+\.[0-9]+)$ ]]; then
BRANCH="${BASH_REMATCH[1]}"
PATCH=0
else
echo "UNKNOWN — Unrecognized version format: $WP_VERSION"
exit 2
fi
# Check if branch is in affected range
MAJOR=$(echo "$BRANCH" | cut -d. -f1)
MINOR=$(echo "$BRANCH" | cut -d. -f2)
# Versions before 4.7 are EOL and not backported — assume vulnerable
if (( MAJOR < 4 )) || { (( MAJOR == 4 )) && (( MINOR < 7 )); }; then
echo "VULNERABLE — WordPress $WP_VERSION is below 4.7 (EOL, no backport available)"
exit 1
fi
# Versions 7.2+ are not affected
if (( MAJOR > 7 )) || { (( MAJOR == 7 )) && (( MINOR >= 2 )); }; then
echo "PATCHED — WordPress $WP_VERSION is beyond the affected range"
exit 0
fi
# Look up required patch level for this branch
if [[ -v PATCHED_VERSIONS[$BRANCH] ]]; then
REQUIRED_PATCH=${PATCHED_VERSIONS[$BRANCH]}
if (( PATCH >= REQUIRED_PATCH )); then
echo "PATCHED — WordPress $WP_VERSION >= $BRANCH.$REQUIRED_PATCH"
exit 0
else
echo "VULNERABLE — WordPress $WP_VERSION < $BRANCH.$REQUIRED_PATCH (needs $BRANCH.$REQUIRED_PATCH+)"
exit 1
fi
else
echo "UNKNOWN — Branch $BRANCH not in known affected/patched list"
exit 2
fi- WordPress 7.1.1 Security Release — Official
- Comment2Shell: Pre-Auth XSS to RCE Research — Rafie Muhammad
- Patchstack Advisory — WordPress 7.1.1
- OffSeq Threat Radar — CVE-2026-93485
- HOL Blog — WordPress 7.1.1 Unauth Comment XSS
- SecurityOnline — WordPress Stored XSS PoC Disclosed
- Censys — WordPress EOL PHP and Exposure Data
- Tenable — CVE-2026-93485
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.