WordPress 7.1.1 landed on 17 September 2026. It’s a security and maintenance release with 11 security fixes and 17 Core bug fixes. The headline issue is an unauthenticated stored cross-site scripting (XSS) vulnerability in wpautop(), the function that turns line breaks into paragraphs on nearly every piece of content WordPress renders.
Patchstack customers are protected for the stored XSS. We still recommend updating to the most recent version of WordPress available.
✌️ Our users are protected from this vulnerability. Are yours?
Identify vulnerabilities in your plugins and get recommendations for fixes.
Request auditProtect your users, improve server health and earn additional revenue.
Patchstack for hostsUnauthenticated Stored XSS in wpautop()
The headline vulnerability was reported by Rafie Muhammad and affects WordPress Core up to and including 7.1. It carries a CVSS 3.1 score of 7.1 (AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L). CVE-2026-93485 has been assigned to this vulnerability.
The entry point is what matters here. This one needs no account at all. The payload goes in an ordinary comment, through the ordinary comment form, submitted by an anonymous visitor. It gets past wp_kses(), WordPress’s comment sanitiser, because nothing in it looks like the markup wp_kses() exists to strip. It only turns dangerous later, when the comment is displayed and the display filters rearrange it.
The Sink
wpautop() in wp-includes/formatting.php is the one content filter in Core that doesn’t parse HTML. It works on text, with regular expressions, and one of those expressions wasn’t aware of quoted attribute values:
<span style="color:#6a9955">// wp-includes/formatting.php, WordPress <= 7.1</span>
<span style="color:#6a9955">// If a <blockquote> is wrapped with a <p>, move it inside the <blockquote>.</span>
<span style="color:#9cdcfe">$text</span> = <span style="color:#dcdcaa">preg_replace</span>( <span style="color:#ce9178">'|<p><blockquote([^>]*)>|i'</span>, <span style="color:#ce9178">'<blockquote$1><p>'</span>, <span style="color:#9cdcfe">$text</span> );
The capture group ([^>]*) stops at the first > character it meets. That works for a well formed tag, where the first > is the one closing it. It breaks when a > shows up inside a quoted attribute value, because the expression then reads the middle of an attribute as the end of the tag, and moves a <p> element into it.
An attacker doesn’t have to supply that >. A few lines earlier, wpautop() protects newlines that sit inside tags by swapping them for a placeholder:
<span style="color:#6a9955">// Find newlines in all elements and add placeholders.</span>
<span style="color:#9cdcfe">$text</span> = <span style="color:#dcdcaa">wp_replace_in_html_tags</span>( <span style="color:#9cdcfe">$text</span>, <span style="color:#569cd6">array</span>( <span style="color:#ce9178">"
"</span> => <span style="color:#ce9178">' <!-- wpnl --> '</span> ) );
That placeholder is an HTML comment, and an HTML comment ends in -->. So a plain line break inside an attribute value becomes a > inside an attribute value. WordPress’s comment allowlist permits <blockquote cite="">, and a newline inside that cite value isn’t something wp_kses() has any reason to remove. WordPress supplies the character the attack needs.
From there the tag gets torn in half, the attribute’s real closing quote is left stranded, and the remaining display filters finish the job. Attacker controlled text ends up in the part of the tag where attributes go, instead of safely inside an attribute value. The result is script execution in the site’s own origin for any visitor who loads the page, logged in or not. We aren’t publishing the breakout chain or a working payload.
The fix makes the expression aware of quoting, so a > inside a quoted value no longer reads as the end of a tag:
<span style="color:#6a9955">// wp-includes/formatting.php, WordPress 7.1.1</span>
<span style="color:#9cdcfe">$text</span> = <span style="color:#dcdcaa">preg_replace</span>( <span style="color:#ce9178">'!<p><blockquote((?:[^>"\']|"[^"]*"|\'[^\']*\')*)>!i'</span>, <span style="color:#ce9178">'<blockquote$1><p>'</span>, <span style="color:#9cdcfe">$text</span> );
What Limits It
One thing keeps this from being a drive-by: the comment has to be published. On a stock install, comment_previously_approved holds a first-time commenter for moderation, so the payload sits in the queue until a moderator approves it. That slows an attacker down, but moderation isn’t a security control. Approving comments is routine work, the payload looks unremarkable in the moderation queue, and anyone who has had a comment approved before is auto-approved from then on.
Sites that accept public comments should treat this as the priority fix in the release, especially where moderation is delegated or returning commenters are auto-approved.
Timeline
The Rest of the Release
The other ten fixes are mostly access control and disclosure issues, and most needs an account with certain privileges. Contributor-level access was enough for an arbitrary post overwrite and for a path traversal in the REST API templates controller (both reported by Anthropic), and for disclosure of draft and pending post slugs (hermanhms). Any authenticated user could reparent comments, including notes (viridis), and Author-level access was enough to publish changeset posts over XML-RPC that skipped the custom CSS capability check (Ben Bidner of the WordPress Security Team).
The remainder: a stored XSS in custom header images on some themes and an HTML API issue letting modified text escape an HTML comment (both Jeremy Felt of the WordPress Security Team), a crafted URL that could install and preview a theme from WordPress.org (Paulos Yibelo and pwn.ai), a Multisite issue letting a site administrator network-activate a network-only plugin (Jesse McNeil), and an information disclosure exposing the title of a private parent post (HDWSec).
Update Now
WordPress 7.1.1 is available from the Dashboard under Updates, or from WordPress.org directly. Sites with automatic background updates enabled will pick it up on their own. WordPress backported these fixes to older branches as far back as 4.7, and the release notes cover which branch got which fix, but only the most recent version of WordPress is actively supported and that’s the version to be on.


