OPEN-WEBUI · CVE-2026-109300 · AI agents & MCP
FIX → 0.11.4
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.
first public Sep 27, 2026 · 2 sources
Could this affect your app?
Free first check from your website. Connect your repo for the full answer.
Any Open WebUI instance from 0.6.31 up to but not including 0.11.4 with user accounts that can post messages is exposed, since the script runs in other users' browsers when they view the message or a citation preview. The primary surface is channel messages, which need the Channels feature enabled by an admin and is off by default; main-chat messages and citation previews of knowledge-base documents are reachable without that flag. Instances that run only a single trusted user, or that are on 0.11.4 or later, can skip it.
Not affected if single-user-instance, version-0.11.4-or-later
Who cares open-webui, python, self-hosted
open-webui version with pip show open-webui; versions from 0.6.31 up to but not including 0.11.4 are affected.ENABLE_CHANNELS setting is turned on, and whether iframeSandboxAllowSameOrigin is enabled in the instance configuration.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.
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.
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 , the sandbox gains and the script can read (session token) and act as the victim, raising the impact to session hijacking. The payload is stored, so it re-executes on every view.
Check it with your coding agent
It reads this page and tells you if your code is affected.
Are you affected?
Ask from here. InfraStack checks the affected versions against your stack and answers in your inbox.
InfraStack checks the affected versions against your stack and answers in Slack, with the evidence and the fix.
Upgrade to 0.11.4
open-webui 0.11.4 (PR #29985 makes embed rendering opt-in and off by default).iframeSandboxAllowSameOriginallow-same-originlocalStorageFixed 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.
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.
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="["<script>...</script>"]">...</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.
@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.
This page as .md · .json · CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
NVD data is provided by NIST and is public domain. Posts quoted belong to their authors.