GitHub Advisoryadvisory · PyPI
GHSA-hcwp-82g6-8wxc Open WebUI has stored XSS via unsanitized Office/Excel/DOCX file preview rendering ({@html} without DOMPurify)
MEDIUM
Official page ↗
- Aliases
- CVE-2026-45318
- Ecosystem
- PyPI
- Packages
- open-webui
- Severity
- Moderate
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
- Weaknesses
- CWE-79
- Reviewed
- 2026-05-14
Affected packages
• PyPI open-webui: < 0.9.3 → fixed in 0.9.3
Description
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
```svelte
{:else if fileOfficeHtml !== null}
{@html fileOfficeHtml}
```
`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
```svelte
{@html excelHtml}
```
`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
```svelte
{@html docxHtml}
```
`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:
```svelte
{@html DOMPurify.sanitize(token.text, { ADD_ATTR: ['target'] })}
{@html DOMPurify.sanitize($config?.license_metadata?.html)}
{@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`, tag `v0.8.12`)
Steps to Reproduce
PoC 1: Malicious Excel File
1. Create a `.xlsx` file 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:
```xml
]]>
```
2. Upload to Open WebUI
3. File preview renders `docxHtml` → XSS fires
PoC 3: Verify Rendering Path
```javascript
// 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:
```svelte
{@html DOMPurify.sanitize(fileOfficeHtml)}
{@html DOMPurify.sanitize(excelHtml)}
{@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)
Related
Alias · CVE (1)
- CVE-2026-45318 Open WebUI is a self-hosted artificial intelligence platform designed to operate entirely offline. vulnerability
Weakness · CWE (1)
- CWE-79 Improper Neutralization of Input During Web Page Generation weakness
References
- https://github.com/open-webui/open-webui/security/advisories/GHSA-hcwp-82g6-8wxc web
- https://github.com/open-webui/open-webui/security/advisories/GHSA-jwf8-pv5p-vhmc web
- https://nvd.nist.gov/vuln/detail/CVE-2026-45318 advisory
- https://github.com/open-webui/open-webui package
- https://github.com/open-webui/open-webui/releases/tag/v0.9.3 web