Severity by source
CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:P/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
AC:H reflects the drag-trigger specificity and Structure section requirement; PR:L for author role; S:C because victim's admin session is the impacted scope; I:H for potential admin-level action execution.
Primary rating from Vendor (github).
CVSS VectorVendor: github
Lifecycle Timeline
2DescriptionCVE.org
Craft CMS is a content management system (CMS). In versions 5.0.0-RC1 through 5.9.22, an author-level control panel user can store a malicious JavaScript payload in an entry title. When an admin, or any control panel user with saveEntries for the same Structure section, drags another entry under the poisoned entry in table view, the payload executes in the victim’s session. The issue is exploitable because the title is escaped into data-title by the server, decoded again by the browser, read with jQuery .data('title'), and then concatenated into a new HTML string without attribute escaping. To exploit, an attacker must have an existing control panel account (Author role minimum), the victim must perform a drag operation (not just visit the page), and the victim’s session needs to be elevated at trigger time. This issue has been fixed in version 5.9.23.
AnalysisAI
Stored XSS in Craft CMS 5.0.0-RC1 through 5.9.22 allows an author-level control panel user to execute arbitrary JavaScript in the session of an admin or any privileged user with saveEntries permission on the same Structure section. The vulnerability arises from an HTML encode/decode mismatch: the server safely escapes an entry title into a data-title attribute, but jQuery's .data() method re-decodes the value before it is concatenated back into HTML without re-escaping, bypassing the initial sanitization. No active exploitation (CISA KEV) or public exploit code has been identified at time of analysis; the vendor shipped a fix in version 5.9.23.
Technical ContextAI
The root cause is CWE-79 (Improper Neutralization of Input During Web Page Generation - Stored XSS), specifically a second-order injection created by a double encode/decode cycle. The Craft CMS control panel correctly HTML-encodes the entry title when serializing it into the data-title HTML attribute server-side. However, jQuery's .data() API automatically decodes HTML entities when reading any data-* attribute, returning the raw, unescaped string. This decoded value is then concatenated directly into a new HTML fragment during the drag-and-drop reorder operation in Structure-section table view, without re-encoding - introducing the attacker's payload into the DOM as live markup. The affected product is cpe:2.3:a:craftcms:craft_cms:*:*:*:*:*:*:*:* covering versions 5.0.0-RC1 through 5.9.22. The mechanism is a classic jQuery .data() unserialization pitfall where a trusted DOM path is assumed to be safe after the first encoding pass.
RemediationAI
Upgrade Craft CMS to version 5.9.23 or later, which resolves this issue per the vendor security advisory GHSA-xrqc-p465-2xvg (commit 162321e899cc97517fb6f5a02b5528f549d0c6cc). If an immediate upgrade is not feasible, restrict untrusted author-level accounts from creating or editing entries in any Structure-type sections - this eliminates access to the drag-reorder trigger, though it prevents those users from contributing to Structure sections entirely. As an additional defensive measure, audit existing entry titles in all Structure sections for suspicious script content (e.g., strings containing <script, javascript:, onerror=, or event handler patterns) before applying the patch, since malicious payloads may already be stored. Do not rely solely on admin-side Content Security Policy headers as a compensating control, as CSP effectiveness depends on header configuration that varies by deployment.
Same weakness CWE-79 – Cross-site Scripting (XSS)
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-41153
GHSA-xrqc-p465-2xvg