CVE-2026-56393 — craftcms/cms
Fix: craftcms/cms@67780a7CVE-2026-56393 is a Cross-site Scripting (XSS) vulnerability in craftcms/cms. A fix is available for craftcms/cms — see the affected versions and patch details below.
Craft CMS - Multiple Stored Cross-Site Scripting in Settings Names and Field Options
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-56393.
EPSS Exploitation Probability
EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.
Real-World Exposure
craftcms/cms🐘craftcms/cmsReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Packagist packages — download data is not available via public APIs for these ecosystems.
Description
Overview of all XSS Reports
Multiple stored XSS vulnerabilities were found in Craft CMS. They were split into 4 reports as follows:
| Report | What's Vulnerable | Why Separate |
|---|---|---|
| This Report (1) | Multiple settings names | Twig Template: _includes/forms/checkbox.twig |
| Report 2 | Entry Types Name | Twig Template: _includes/forms/editableTable.twig |
| Report 3 | Card Attributes in Field Layout | helpers/Cp.php |
| Report 4 (Commerce) | Product Type Name | Source in Commerce, sink in CMS - will report this one via Commerce GHSA |
Reports 2, 3, and 4 are clearly distinct locations. For this report (Report 1), it was not clear whether to split or consolidate these 7 bugs. The bug report was consolidated and the final categorization should be left to the judgement of the user.
Note: This overview is only in this Report. Other reports only reference this one.
Summary
Stored XSS in multiple settings. Names/labels are rendered without sanitization via checkbox.twig template which uses {{ label|raw }}.
Affected Sources
| # | Source (injection point) | Sink (where payload reflects) |
|---|---|---|
| 1 | Section Name (/admin/settings/sections) | Entries field -> Sources checklist |
| 2 | Volume Name (/admin/settings/assets/volumes/{vol_id}) | Assets field -> Sources checklist |
| 3 | User Group Name (/admin/settings/users/groups) | Users field -> Sources, User permissions page |
| 4 | Global Set Name (/admin/settings/globals) | User permissions page |
| 5 | Generated Fields Name (Volumes, Users, etc.) | Card Attributes checkboxes |
| 6 | Checkboxes & Radio Buttons Field Option Label (/admin/settings/fields) | User profile pages |
| 7 | Custom Sources Label (/admin/users -> Customize Sources) | Users field -> Sources checklist |
Proof of Concept
Required Permissions (Attacker)
- Admin access
allowAdminChangesis enabled in production, which is against our security recommendations.
Bugs 1-3: Section, Volume, User Group Names
- Log in as admin.
- Inject payload in one of these:
- Settings -> Sections -> Create/edit section -> Name
- Settings -> Assets -> Volumes -> Create/edit volume -> Name
- Settings -> Users -> User Groups -> Create/edit group -> Name
- Set Name to:
<img src=x onerror="alert('XSS')">
- Save.
- Go to Settings -> Fields -> Create new field.
- To trigger the XSS payload: Set Field Type to "Entries" (for Sections), "Assets" (for Volumes), or "Users" (for User Groups). The alert fires when the Sources checkbox list renders.
Note: User Group Name also reflects on User permissions page under User Groups section (/admin/users/{id}/permissions).
Bug 4: Global Set Name
- Go to Settings -> Globals (
/admin/settings/globals). - Create/edit a Global Set, set Name to payload.
- Save.
- Go to Users -> Edit any user -> Permissions tab (
/admin/users/{id}/permissions). - Alert fires because our payload got rendered in the "Global Sets" permissions section without encoding/sanitization.
Bug 5: Generated Fields Name
- Go to Settings -> Assets -> Volumes -> Create/Edit a volume.
- Scroll to Generated Fields section.
- Add a field, set Name to payload:
<img src=x onerror="alert('XSS')">
- Save & Notice the alert. The payload renders in the Card Attributes checkbox list below it.
Bug 6: Checkboxes/Radio Buttons Option Label
- Go to Settings -> Fields (
/admin/settings/fields). - Create new field, set Field Type to "Checkboxes" or "Radio Buttons".
- In Field Options, add an option with Label set to payload.
- Save the field.
- Go to Settings -> Users -> User Profile Fields (
/admin/settings/users/fields). - Add the created field to the layout and save.
- Alert fires on any user profile page (
/admin/users/{id}).
Bug 7: Custom Sources Label
- Go to Users (
/admin/users). - Click the three dots icon -> Customize Sources.
- Create a new custom source, set Label to payload.
- Save.
- Go to Settings -> Fields -> Create new field.
- Set Field Type to "Users".
- Alert fires in the Sources checkbox list.
Resources
https://github.com/craftcms/cms/commit/943152d2246b36f12adf161a03b8695b773d9276 https://github.com/craftcms/cms/commit/67780a778c6ec04e68e64a0b1177c168306144a2
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐘Packagist | craftcms/cms | ≥ 5.0.0-RC1&&< 5.9.0-beta.1 | 5.9.0-beta.1composer require craftcms/cms:^5.9.0-beta.1 |
| 🐘Packagist | craftcms/cms | ≥ 4.0.0-RC1&&< 4.17.0-beta.1 | 4.17.0-beta.1composer require craftcms/cms:^4.17.0-beta.1 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for craftcms/cms, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update craftcms/cms to 5.9.0-beta.1 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-56393 is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like CVE-2026-56393 can be triaged on real exposure rather than presence alone.
Tailored to CVE-2026-56393. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is CVE-2026-56393 in your dependencies?
O3 Security finds CVE-2026-56393 across Packagist dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.