CVE-2026-45318: Open WebUI has stored XSS via unsanitized Office/Excel/DOCX file preview rendering ({@html} without DOMPurify)
Related advisory This advisory tracks a regression of the original Excel-preview XSS that was publicly disclosed and patched under GHSA-jwf8-pv5p-vhmc (patched in v0.8.0). The same root cause — XLSX.utils.sheettohtml() output rendered via {@html excelHtml} without DOMPurify — was reintroduced sometime after v0.8.0 and is exploitable again as of v0.8.12 and through the version range listed above.
Published May 14, 2026 · Updated May 19, 2026
Affected packages
open-webui
- Ecosystem
- PyPI
- Affected
- <= 0.9.2
- Fixed in
- 0.9.3
- Check
pip show open-webui
Advisory details
From the GitHub Advisory Database (CC BY 4.0).
Related advisory
This advisory tracks a regression of the original Excel-preview XSS that was publicly disclosed and patched under GHSA-jwf8-pv5p-vhmc (patched in v0.8.0). The same root cause — XLSX.utils.sheet_to_html() output rendered via {@html excelHtml} without DOMPurify — was reintroduced sometime after v0.8.0 and is exploitable again as of v0.8.12 and through the version range listed above. This advisory additionally covers the related fileOfficeHtml sink in src/lib/components/chat/FileNav.svelte (lines 458 and 1285) which was not part of the jwf8 advisory's scope.
Summary
Open WebUI renders user-uploaded Office files (Excel, DOCX) as HTML using Svelte's {@html} directive without DOMPurify sanitization. While the codebase has DOMPurify available and uses it in 9 out of 23 {@html} locations (39%), three file-preview rendering paths bypass it entirely, allowing Stored XSS when a user uploads a malicious document.
This is a classic defense propagation failure: the sanitization primitive exists in the codebase but is not consistently applied to all rendering surfaces.
Root Cause
The defense primitive exists: DOMPurify.sanitize() is imported and used in components like General.svelte, MarkdownInlineTokens.svelte, Banner.svelte, and SVGPanZoom.svelte.
But 3 file-preview paths skip it:
Occurrence 1: FilePreview.svelte — Office HTML
File: src/lib/components/chat/FileNav/FilePreview.svelte line 324
{:else if fileOfficeHtml !== null}
{@html fileOfficeHtml} <!-- NO DOMPurify! -->
fileOfficeHtml is generated from user-uploaded Office files (PPT, DOC, etc.) converted to HTML. The HTML is rendered directly without sanitization.
Occurrence 2: FileItemModal.svelte — Excel HTML
File: src/lib/components/common/FileItemModal.svelte line 560
{@html excelHtml} <!-- NO DOMPurify! -->excelHtml is generated from user-uploaded Excel files converted to HTML tables. No sanitization applied.
Occurrence 3: FileItemModal.svelte — DOCX HTML
File: src/lib/components/common/FileItemModal.svelte line 590
{@html docxHtml} <!-- NO DOMPurify! -->docxHtml is generated from user-uploaded DOCX files converted to HTML. No sanitization applied.
Contrast with Sanitized Paths
For comparison, the same codebase correctly sanitizes in other locations:
<!-- MarkdownInlineTokens.svelte:130 — SAFE -->
{@html DOMPurify.sanitize(token.text, { ADD_ATTR: ['target'] })}
<!-- General.svelte:276 — SAFE -->
{@html DOMPurify.sanitize($config?.license_metadata?.html)}
<!-- Banner.svelte:103 — SAFE -->
{@html DOMPurify.sanitize(marked.parse(...))}Defense Propagation Gap
| Metric | Value |
| Total `{@html}` usages | 23 |
| With DOMPurify | 9 (39%) |
| **Without DOMPurify** | **14 (61%)** |
| Confirmed exploitable (file preview) | **3** |The remaining 11 unsanitized {@html} usages include syntax highlighting (hljs), KaTeX math rendering, and marked.parse() with sanitizeResponseContent() pre-processing — these have varying levels of inherent safety but still represent inconsistent defense application.
Tested Version
- Open WebUI v0.8.12 (commit
9bd8425, tagv0.8.12)
Steps to Reproduce
PoC 1: Malicious Excel File
- Create a
.xlsxfile with a cell containing: ```
(Using a library like openpyxl to inject raw HTML into cell values)
2. Upload the file to Open WebUI via the chat file upload
3. When any user previews the file → `excelHtml` renders the injected HTML → **XSS fires**
### PoC 2: Malicious DOCX File
1. Create a `.docx` file with embedded HTML:<![CDATA[]]>
2. Upload to Open WebUI
3. File preview renders `docxHtml` → **XSS fires**
### PoC 3: Verify Rendering Path
// In browser devtools on Open WebUI, after uploading a file: // The file preview component renders: // FileItemModal → {@html excelHtml} // no DOMPurify // FileItemModal → {@html docxHtml} // no DOMPurify // FilePreview → {@html fileOfficeHtml} // no DOMPurify
// Compare with safe path: // NotebookView → {@html DOMPurify.sanitize(toStr(output.data['text/html']))} // sanitized!
## Impact
- **Stored XSS** — malicious file is stored server-side, XSS fires for every user who previews it
- **Session hijacking** via `document.cookie` theft
- **Account takeover** — attacker can perform actions as the victim user
- **Data exfiltration** — read chat history, API keys, uploaded documents
- **Multi-user environments** — shared Open WebUI instances are especially vulnerable (one malicious upload affects all viewers)
- **Defense propagation failure** — DOMPurify is available and used elsewhere, but not applied to file preview paths
## Suggested Remediation
Apply DOMPurify to all three file preview paths:
<!-- FilePreview.svelte:324 — FIX --> {@html DOMPurify.sanitize(fileOfficeHtml)}
<!-- FileItemModal.svelte:560 — FIX --> {@html DOMPurify.sanitize(excelHtml)}
<!-- FileItemModal.svelte:590 — FIX --> {@html DOMPurify.sanitize(docxHtml)}
Alternatively, adopt a **defense-by-default pattern**: create a wrapper component that always applies DOMPurify, making unsanitized `{@html}` usage a code review flag.
## References
- CWE-79: Improper Neutralization of Input During Web Page Generation (XSS)
- OWASP XSS Prevention Cheat Sheet
- GHSA-x75g-rp99-qqpx: Previous Open WebUI report (DNS rebinding TOCTOU, different vulnerability class)Credited to foodlook, Classic298.
References
- https://github.com/open-webui/open-webui/security/advisories/GHSA-hcwp-82g6-8wxc
- https://github.com/open-webui/open-webui/security/advisories/GHSA-jwf8-pv5p-vhmc
- https://github.com/open-webui/open-webui/releases/tag/v0.9.3
- https://nvd.nist.gov/vuln/detail/CVE-2026-45318
- https://github.com/advisories/GHSA-hcwp-82g6-8wxc
How this page is made: the data panel comes from the GitHub Advisory Database, CISA’s KEV catalog, the NVD and FIRST EPSS, and updates twice a day. No analysis has been written for this entry yet. Methodology
More Open WebUI vulnerabilities
All Open WebUI entriesCVE-2026-87011
Open WebUI: Unauthenticated requests can stall the server via uncached OIDC fetches in back-channel logout
high7.5Sep 10, 2026CVE-2026-87012
Open WebUI: Any authenticated user can suppress calendar alerts instance-wide via a non-numeric alert value
medium4.3Sep 10, 2026CVE-2026-87013
Open WebUI: Any authenticated user can start a non-terminating request via a folder parent cycle
medium4.3Sep 10, 2026CVE-2026-87014
Open WebUI: Admin demoted through SSO role sync keeps read and write access to all users' notes
medium6.5Sep 10, 2026CVE-2026-87015
Open WebUI: A user's session cookies are sent to tool servers configured for bearer authentication
medium6.8Sep 10, 2026CVE-2026-87016
Open WebUI: Sign-in as another user via wildcard characters in the OAuth subject claim on SQLite
high8.1Sep 10, 2026
