Saleor Rich Text (EditorJS) Field Stored XSS (CVE-2026-22849)
by Lukasz Rybak (with Quyền Vũ) · 2026-07-05
- Severity
- High
- CVE
- CVE-2026-22849 (GHSA-8jcj-r5g2-qrpv)
- Category
- web
- Affected product
- Saleor (open-source e-commerce platform), rich text fields (EditorJS content on pages/products)
- Affected versions
- Prior to 3.22.27, 3.21.43, 3.20.108
- Disclosed
- 2026-07-05
- Patch status
- unpatched
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-05 |
| Last Updated | 2026-04 |
| Author / Researcher | Lukasz Rybak (with Quyền Vũ) |
| CVE / Advisory | CVE-2026-22849 (GHSA-8jcj-r5g2-qrpv) |
| Category | web |
| Severity | High |
| CVSS Score | Not specified in source |
| Status | PoC |
| Tags | saleor, stored-xss, editorjs, graphql, ecommerce, session-hijacking, cwe-79 |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | Saleor (open-source e-commerce platform), rich text fields (EditorJS content on pages/products) |
| Versions Affected | Prior to 3.22.27, 3.21.43, 3.20.108 |
| Language / Platform | Saleor backend (Python/GraphQL); PoC written in Python against Saleor’s GraphQL API |
| Authentication Required | Yes (staff/editor account able to modify rich text fields) |
| Network Access Required | Yes |
Summary
Saleor stores rich text content (page bodies, product descriptions, etc.) as EditorJS block JSON, and is supposed to run this content through a server-side HTML cleaner before persisting and rendering it. In the affected versions that cleaning step was not enforced, so a user able to edit a rich text field could embed raw, active HTML (such as an <img onerror=...> payload) inside an EditorJS block. That payload is stored verbatim and later rendered unsanitized in the Saleor dashboard and/or storefront, producing a stored XSS that can target other staff members and potentially steal their access/refresh tokens. The upstream researcher’s repository is an advisory writeup without a standalone script; this folder’s exploit.py re-derives a minimal, runnable PoC directly from that advisory’s own description of the bug so the technique can be exercised via Saleor’s GraphQL API.
Vulnerability Details
Root Cause
Saleor accepted EditorJS-format rich text JSON for fields such as page/product content without passing it through its HTML-cleaning step, allowing raw inline HTML/JS embedded inside block data (e.g. a paragraph block’s text) to be stored and later rendered without sanitization.
Attack Vector
- Attacker (a staff/editor account with rich-text field edit permission) authenticates to Saleor’s GraphQL API.
- Attacker submits a mutation (e.g.
pageUpdate) whosecontentis EditorJS JSON containing an inline HTML XSS payload (such as an<img src=x onerror=...>tag) inside a block’s text. - Saleor stores the content without cleaning the embedded HTML.
- When another staff member (dashboard) or a storefront visitor views the affected page/product, the unsanitized HTML renders and the embedded script executes, allowing theft of session/refresh tokens or other in-browser data.
Impact
Stored cross-site scripting that can compromise other staff members’ dashboard sessions (including access/refresh token theft) or affect storefront visitors viewing the tampered content.
Environment / Lab Setup
Target: Saleor instance prior to 3.22.27 / 3.21.43 / 3.20.108, GraphQL API reachable
Attacker: Python 3, requests (pip install requests), a staff/editor account with rich-text edit permissions
Proof of Concept
PoC Script
See
exploit.pyin this folder.
| |
The script authenticates via Saleor’s tokenCreate GraphQL mutation, submits a pageUpdate mutation whose content is EditorJS JSON embedding an <img onerror=...> XSS payload inside a paragraph block, and then re-queries the page to confirm the payload was stored verbatim (i.e. unsanitized) rather than cleaned.
Detection & Indicators of Compromise
Signs of compromise:
- Unexpected differences reported by Saleor’s
clean_editorjs_fieldsmanagement command on existing rich text fields - Rich text (page/product description) content containing raw event-handler attributes or
<script>tags - Staff accounts exhibiting session/token misuse shortly after viewing a modified page or product in the dashboard
Remediation
| Action | Detail |
|---|---|
| Primary fix | Upgrade Saleor to 3.22.27, 3.21.43, or 3.20.108 or later |
| Interim mitigation | Run ./manage.py clean_editorjs_fields (add --apply to fix) to detect and clean already-stored malicious rich text; additionally apply a client-side sanitizer such as DOMPurify if upgrading isn’t immediately possible |
References
Notes
Mirrored from https://github.com/lukasz-rybak/CVE-2026-22849 on 2026-07-05.
| |