---
id: "CVE-2026-109300"
page: "https://infrastack.ai/live/CVE-2026-109300"
kind: "vulnerability"
aliases: ["CVE-2026-109300", "GHSA-9wj4-mcm3-ppj6"]
title: "Stored XSS via user-authored tool-call embeds in the Markdown renderer"
severity: "medium"
cvss: 5.1
epss: null
exploited: false
status: "open"
category: "ai-tooling"
products: [{"name": "open-webui", "fixed": ["0.11.4"], "affected": ">= 0.6.31, < 0.11.4", "ecosystem": "pypi"}]
ecosystems: ["pypi"]
tags: ["ai-tooling", "cwe-79", "open-webui", "python", "self-hosted"]
not_affected_if: ["single-user-instance", "version-0.11.4-or-later"]
published_at: "2026-09-27T19:27:08+00:00"
first_seen_at: "2026-11-09T22:53:26+00:00"
updated_at: "2026-11-09T23:10:12+00:00"
sources: [{"source": "ghsa-repo", "url": "https://github.com/open-webui/open-webui/security/advisories/GHSA-9wj4-mcm3-ppj6", "first_seen_at": "2026-11-09T22:53:26+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-109300", "first_seen_at": "2026-11-09T23:10:12+00:00"}]
exploit_sources: []
---

# Stored XSS via user-authored tool-call embeds in the Markdown renderer

Link for people: https://infrastack.ai/live/CVE-2026-109300 (this .md is for agents)

Open WebUI rendered tool-call blocks typed by users inside messages as live sandboxed iframes with scripts enabled, so any logged-in user can plant a script that runs for every viewer of that message. The stored payload re-executes each time the message is opened, and where the operator has enabled same-origin iframes the script can read the session token and act as the victim.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- pypi:open-webui affected >= 0.6.31, < 0.11.4 fixed 0.11.4

## How to check

- Check the installed `open-webui` version with `pip show open-webui`; versions from `0.6.31` up to but not including `0.11.4` are affected.
- Check whether the `ENABLE_CHANNELS` setting is turned on, and whether `iframeSandboxAllowSameOrigin` is enabled in the instance configuration.

## Fix

- `open-webui` `0.11.4` (PR #29985 makes embed rendering opt-in and off by default).

## Timeline

- 2026-11-09T22:53:26+00:00 ghsa-repo https://github.com/open-webui/open-webui/security/advisories/GHSA-9wj4-mcm3-ppj6
- 2026-11-09T23:10:12+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-109300

## Documents

- [advisory] Maintainer's advisory: github.com https://github.com/open-webui/open-webui/security/advisories/GHSA-9wj4-mcm3-ppj6
- [advisory] Third-party advisory: www.vulncheck.com https://www.vulncheck.com/advisories/open-webui-0.6.31-before-0.11.4-stored-xss-via-tool-call-embeds

## From the sources

# Stored XSS via user-authored tool-call embeds in the Markdown renderer

## Summary
Any authenticated user can execute arbitrary JavaScript in other users' browsers by sending content shaped as a tool-call `<details>` block. The Markdown renderer parsed the block's `embeds` attribute without distinguishing server-generated tool-call output from user-authored input, decoded and JSON-parsed it, and mounted each element in a sandboxed iframe with scripts enabled, so it ran at render time for every viewer. The missing control is a trust gate separating user content from the tool-call embed path.

## Preconditions
An authenticated account on the instance. The primary demonstrated surface is channel messages, which requires the Channels feature enabled by an admin (`ENABLE_CHANNELS`, off by default); the same gadget also reaches main-chat user messages and citation previews of retrieved documents, which need no special feature flag. No elevated role is required. By default the embed iframe is sandboxed `allow-scripts` without `allow-same-origin`, so the injected script runs in an opaque origin.

## Impact
The injected script executes in a null-origin sandboxed iframe for anyone who views the message or opens the citation. In the default configuration it cannot read the viewer's session token or make same-origin authenticated requests; the confirmed default primitive is contained script execution and convincing in-app phishing content rendered inside the interface. Where an operator has turned on `iframeSandboxAllowSameOrigin`, the sandbox gains `allow-same-origin` and the script can read `localStorage` (session token) and act as the victim, raising the impact to session hijacking. The payload is stored, so it re-executes on every view.

## Fix
Fixed in 0.11.4 by PR #29985. Embed rendering is now opt-in: the flag defaults off and is forwarded through every Markdown render path, including the standalone tool-call branch, colon fences and alerts. Assistant responses opt in only for the viewer's own chat; channel messages and read-only/shared views pass it explicitly off, so user-authored content can no longer reach the embed iframe. Upgrading to 0.11.4 fully resolves the issue with no additional configuration.

## Root cause
The tool-call embed sink lives in the shared Markdown renderer: `ToolCallDisplay.svelte` and `ConsecutiveDetailsGroup.svelte` read the `embeds` attribute off a `<details type="tool_calls">` token and mount each element in `FullHeightIframe` with `allowScripts={true}`. The renderer never distinguished tokens produced by the tool-execution pipeline from tokens parsed out of arbitrary user-authored message content, and the later `allowEmbeds` guard was applied only to the grouped path, so a single standalone details block bypassed it entirely and reached the iframe on every surface that renders user content.

## Proof of concept
Reproduced on stock 0.11.3 with default settings and Channels enabled. A non-admin account posted a channel message whose content was `<details type="tool_calls" embeds="[&quot;&lt;script&gt;...&lt;/script&gt;&quot;]">...</details>`. Opening the channel rendered one iframe with `sandbox="allow-scripts allow-popups allow-downloads"` and the attacker HTML in `srcdoc`, and the injected script executed in the viewer's browser (null origin). The same message on 0.11.4 renders no iframe and no script runs.

## Credits
@KadirArslan: channel messages, original report and proof of concept.
@5yu4n: cross-user delivery through channel direct messages.
@ComputerOnFire: citation previews of knowledge-base documents, and the ungated standalone-block path.

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
