Saleor Stored XSS via Unrestricted File Upload (CVE-2026-23499)
by Lukasz Rybak (lukasz-rybak) · 2026-07-05
- Severity
- High
- CVE
- CVE-2026-23499
- Category
- web
- Affected product
- Saleor (saleor/saleor)
- Affected versions
- Prior to 3.22.27 / 3.21.43 / 3.20.108 (fixed in those releases); Saleor Cloud is not impacted
- Disclosed
- 2026-07-05
- Patch status
- patched
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-05 |
| Last Updated | 2026-04 |
| Author / Researcher | Lukasz Rybak (lukasz-rybak) |
| CVE / Advisory | CVE-2026-23499 |
| Category | web |
| Severity | High |
| CVSS Score | Not specified in source |
| Status | PoC |
| Tags | saleor, stored-xss, unrestricted-file-upload, svg-xss, session-hijack, graphql, javascript |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | Saleor (saleor/saleor) |
| Versions Affected | Prior to 3.22.27 / 3.21.43 / 3.20.108 (fixed in those releases); Saleor Cloud is not impacted |
| Language / Platform | Python/Django backend, browser-rendered media |
| Authentication Required | Yes — authenticated staff user or App |
| Network Access Required | Yes |
Summary
Saleor allowed authenticated staff users or Apps to upload arbitrary file types through its media-upload functionality, including HTML and SVG files containing embedded JavaScript. In deployments where uploaded media is served from the same origin as the admin dashboard, and no Content-Disposition: attachment header forces a download, an uploaded malicious file executes in the browser when opened, giving an attacker a stored XSS against other dashboard users. Because the payload runs in the dashboard’s origin, it can be used to steal session or refresh tokens from other staff members.
Vulnerability Details
Root Cause
The media/file upload path does not restrict or sanitize uploaded content types (notably HTML and SVG containing <script>), and affected deployments serve that media same-origin with the dashboard without a forced-download Content-Disposition header — allowing the browser to execute the uploaded content as if it were first-party.
Attack Vector
- An attacker with staff or App-level access to the Saleor dashboard uploads a malicious HTML or SVG file containing embedded JavaScript via the media/file upload functionality.
- If the target deployment serves media from the same domain as the dashboard (e.g.
example.com/media/alongsideexample.com/dashboard/) without aContent-Disposition: attachmentheader, the file is stored and directly browsable. - The attacker gets another staff member to open the uploaded file’s URL (directly, via a shared link, or through normal dashboard workflows).
- The victim’s browser renders/executes the embedded script in the dashboard’s origin, letting the attacker exfiltrate the victim’s session or refresh tokens.
Impact
Stored cross-site scripting against Saleor dashboard users, enabling theft of staff session/refresh tokens and potential account takeover or privilege escalation between staff accounts. Deployments that host media on a separate domain, or that send Content-Disposition: attachment for media, are not affected.
Environment / Lab Setup
Target: Saleor instance < 3.22.27 / 3.21.43 / 3.20.108, media hosted same-origin as the dashboard
Attacker: Authenticated staff or App account, standard web browser
Proof of Concept
PoC Script
The upstream source repository is advisory-only: it documents the vulnerability, impact, and a defensive scanning command, but does not publish a standalone exploit script or malicious sample file. No script is included in this folder for that reason.
| |
The advisory instead documents a defensive Django management command that ships with fixed Saleor versions to audit existing uploads for files that would now be rejected:
| |
Detection & Indicators of Compromise
Signs of compromise:
- Unexpected
.htmlor.svgfiles in the media storage (filesystem, S3 bucket, etc.) uploaded by staff/App accounts. - Staff session/refresh token misuse shortly after a suspicious media file was accessed.
Remediation
| Action | Detail |
|---|---|
| Primary fix | Upgrade to Saleor 3.22.27, 3.21.43, or 3.20.108 (or later), and run ./manage.py remove_invalid_files to audit existing uploads. |
| Interim mitigation | Serve media from a separate domain from the dashboard, configure Content-Disposition: attachment for media responses, and/or set a restrictive Content-Security-Policy on the media host. |
References
Notes
Mirrored from https://github.com/lukasz-rybak/CVE-2026-23499 on 2026-07-05.