{"id":"CVE-2026-109300","kind":"vulnerability","aliases":["CVE-2026-109300","GHSA-9wj4-mcm3-ppj6"],"related":[],"title":"Stored XSS via user-authored tool-call embeds in the Markdown renderer","description":"# Stored XSS via user-authored tool-call embeds in the Markdown renderer\r\n\r\n## Summary\r\nAny 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.\r\n\r\n## Preconditions\r\nAn 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.\r\n\r\n## Impact\r\nThe 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.\r\n\r\n## Fix\r\nFixed 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.\r\n\r\n## Root cause\r\nThe 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.\r\n\r\n## Proof of concept\r\nReproduced 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.\r\n\r\n## Credits\r\n@KadirArslan: channel messages, original report and proof of concept.\r\n@5yu4n: cross-user delivery through channel direct messages.\r\n@ComputerOnFire: citation previews of knowledge-base documents, and the ungated standalone-block path.","summary":"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.","severity":"medium","cvss":5.1,"epss":null,"exploited":false,"exploited_at":null,"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"],"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.\n- 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).","status":"open","published_at":"2026-09-27T19:27:08+00:00","first_seen_at":"2026-11-09T22:53:26+00:00","triaged_at":"2026-11-09T23:01:14+00:00","updated_at":"2026-11-09T23:10:12+00:00","category":"ai-tooling","confidence":0.85,"triage":{"at":"2026-11-09T23:01:14Z","model":"claude-haiku-5-5","output":{"fix":"- `open-webui` `0.11.4` (PR #29985 makes embed rendering opt-in and off by default).","reach":"network","title":"Open WebUI: user messages can run scripts in other users' browsers","impact":"medium","summary":"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.","audience":"businesses","category":"ai-tooling","nicknames":[],"who_cares":["open-webui","self-hosted","python"],"confidence":0.85,"fix_status":"available","needs_auth":"yes","worst_case":"script runs in viewers' browsers; session hijack if same-origin enabled","analyst_note":"","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.\n- Check whether the `ENABLE_CHANNELS` setting is turned on, and whether `iframeSandboxAllowSameOrigin` is enabled in the instance configuration.\n- unknown for anything else; the sources do not give further checks.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["version-0.11.4-or-later","single-user-instance"],"who_is_affected":"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.","user_interaction":"yes","product_ecosystem":"","needs_special_setup":"no","severity_if_unknown":"unknown"},"cost_usd":0.000941,"input_tokens":5786,"output_tokens":725,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-109300':17A,25A '-2026':16A,24A '-79':33B '/shared':452C '0.11.3':575C '0.11.4':401C,472C,633C '29985':404C '5yu4n':651C '9wj4':20A 'account':217C,586C 'act':108B,376C 'addit':479C 'admin':236C,585C 'ai':30B 'ai-tool':29B 'alert':434C 'allow':277C,281C,364C,603C,606C,609C 'allow-download':608C 'allow-popup':605C 'allow-same-origin':280C,363C 'allow-script':276C,602C 'allowemb':540C 'allowscript':512C 'also':245C 'anyon':306C 'app':346C 'appli':543C 'arbitrari':132C,531C 'assist':435C 'attack':613C 'attribut':156C,501C 'authent':128C,216C,332C 'author':6A,117C,169C,461C,534C 'base':666C 'block':47B,147C,153C,554C,673C 'branch':430C 'browser':137C,626C 'bypass':555C 'call':9A,46B,120C,146C,164C,211C,429C,486C 'cannot':320C 'caus':482C 'channel':226C,231C,238C,446C,580C,589C,596C,643C,657C 'chat':249C,445C 'citat':253C,314C,661C 'colon':431C 'computeronfir':660C 'concept':571C,650C 'configur':318C,480C 'confirm':335C 'consecutivedetailsgroup.svelte':497C 'contain':339C 'content':140C,206C,348C,462C,536C,568C,592C 'control':199C 'convinc':343C 'credit':641C 'cross':653C 'cross-us':652C 'cve':15A,23A 'cwe':32B 'decod':171C 'default':241C,270C,317C,336C,414C,577C 'deliveri':655C 'demonstr':223C 'detail':553C 'direct':658C 'distinguish':158C,517C 'document':257C,667C 'download':610C 'element':180C,508C 'elev':265C 'emb':10A,121C,155C,212C,272C,405C,468C,487C,500C 'enabl':59B,95B,187C,233C,237C,581C 'entir':557C 'everi':73B,195C,396C,420C,563C 'execut':83B,131C,297C,341C,394C,524C,621C 'explicit':456C 'featur':232C,262C 'fenc':432C 'fix':398C,399C 'flag':263C,413C 'forward':418C 'fullheightifram':510C 'fulli':473C 'gadget':244C 'gain':362C 'gate':203C 'generat':161C 'ghsa':19A 'ghsa-9wj4-mcm3-ppj6':18A 'group':547C 'guard':541C 'hijack':385C 'host':40B 'html':614C 'ifram':56B,99B,184C,273C,304C,469C,561C,599C,636C 'iframesandboxallowsameorigin':359C 'impact':293C,382C 'in-app':344C 'includ':424C 'inject':286C,295C,619C 'input':170C 'insid':51B,350C 'instanc':220C 'interfac':352C 'issu':476C 'javascript':133C 'json':174C 'json-pars':173C 'kadirarslan':642C 'knowledg':665C 'knowledge-bas':664C 'later':539C 'live':54B,489C 'localstorag':372C 'log':63B 'logged-in':62B 'longer':465C 'main':248C 'main-chat':247C 'make':328C 'markdown':13A,124C,149C,421C,493C 'mcm3':21A 'messag':52B,77B,87B,227C,251C,310C,447C,535C,590C,631C,644C,659C 'miss':198C 'mount':178C,506C 'need':259C 'never':516C 'non':584C 'non-admin':583C 'null':301C,627C 'null-origin':300C 'one':598C 'opaqu':291C 'open':27A,35B,41B,89B,312C,594C 'open-webui':26A,34B 'oper':93B,355C 'opt':410C,437C 'opt-in':409C 'origin':98B,283C,292C,302C,331C,366C,628C,645C 'output':165C 'pars':151C,175C,528C 'pass':454C 'path':213C,423C,548C,674C 'payload':80B,387C 'phish':347C 'pipelin':525C 'plant':67B 'popup':607C 'post':587C 'ppj6':22A 'pr':403C 'precondit':214C 'preview':254C,662C 'primari':222C 'primit':337C 'produc':519C 'proof':569C,648C 'python':37B 'rais':380C 'ran':190C 're':82B,393C 're-execut':81B,392C 'reach':246C,466C,559C 'read':103B,321C,371C,450C,498C 'read-on':449C 'render':14A,43B,125C,150C,192C,349C,406C,422C,494C,515C,566C,597C,634C 'report':646C 'reproduc':572C 'request':333C 'requir':229C,268C 'resolv':474C 'respons':436C 'retriev':256C 'role':266C 'root':481C 'run':71B,288C,640C 'same-origin':96B,329C 'sandbox':55B,183C,275C,303C,361C,601C 'script':58B,69B,101B,186C,278C,287C,296C,340C,369C,604C,620C,639C 'self':39B 'self-host':38B 'send':139C 'separ':204C 'server':160C 'server-gener':159C 'session':105B,325C,373C,384C 'set':578C 'shape':141C 'share':492C 'singl':551C 'sink':488C 'special':261C 'srcdoc':616C 'standalon':426C,552C,672C 'standalone-block':671C 'stock':574C 'store':1A,79B,112C,389C 'summari':126C 'surfac':224C,564C 'time':85B,193C 'token':106B,326C,374C,504C,518C,527C 'tool':8A,31B,45B,119C,145C,163C,210C,428C,485C,523C 'tool-cal':7A,44B,118C,144C,162C,209C,427C,484C 'tool-execut':522C 'toolcalldisplay.svelte':495C 'true':513C 'trust':202C 'turn':357C 'type':48B 'ungat':670C 'upgrad':470C 'user':5A,50B,65B,116C,129C,136C,168C,205C,250C,460C,533C,567C,654C 'user-author':4A,115C,167C,459C,532C 'via':3A,114C 'victim':111B,379C 'view':308C,397C,453C 'viewer':74B,196C,323C,442C,624C 'webui':28A,36B,42B 'whose':591C 'without':157C,279C 'xss':2A,113C","nicknames":[],"mitigations":[],"who_affected":"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.","tier":"B","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"businesses","plain_action":null,"pkeys":["openwebui"],"ptokens":["open","webui"],"labels":["aitooling","cwe79","medium","openwebui","pypi","python","selfhosted"],"campaign_type":null,"search_a":"'-109300':17A,25A '-2026':16A,24A '9wj4':20A 'author':6A 'call':9A 'cve':15A,23A 'emb':10A 'ghsa':19A 'ghsa-9wj4-mcm3-ppj6':18A 'markdown':13A 'mcm3':21A 'open':27A 'open-webui':26A 'ppj6':22A 'render':14A 'store':1A 'tool':8A 'tool-cal':7A 'user':5A 'user-author':4A 'via':3A 'webui':28A 'xss':2A","search_b":"'-79':33B 'act':108B 'ai':30B 'ai-tool':29B 'block':47B 'call':46B 'cwe':32B 'enabl':59B,95B 'everi':73B 'execut':83B 'host':40B 'ifram':56B,99B 'insid':51B 'live':54B 'log':63B 'logged-in':62B 'messag':52B,77B,87B 'open':35B,41B,89B 'open-webui':34B 'oper':93B 'origin':98B 'payload':80B 'plant':67B 'python':37B 're':82B 're-execut':81B 'read':103B 'render':43B 'run':71B 'same-origin':96B 'sandbox':55B 'script':58B,69B,101B 'self':39B 'self-host':38B 'session':105B 'store':79B 'time':85B 'token':106B 'tool':31B,45B 'tool-cal':44B 'type':48B 'user':50B,65B 'victim':111B 'viewer':74B 'webui':36B,42B","search_c":"'/shared':452C '0.11.3':575C '0.11.4':401C,472C,633C '29985':404C '5yu4n':651C 'account':217C,586C 'act':376C 'addit':479C 'admin':236C,585C 'alert':434C 'allow':277C,281C,364C,603C,606C,609C 'allow-download':608C 'allow-popup':605C 'allow-same-origin':280C,363C 'allow-script':276C,602C 'allowemb':540C 'allowscript':512C 'also':245C 'anyon':306C 'app':346C 'appli':543C 'arbitrari':132C,531C 'assist':435C 'attack':613C 'attribut':156C,501C 'authent':128C,216C,332C 'author':117C,169C,461C,534C 'base':666C 'block':147C,153C,554C,673C 'branch':430C 'browser':137C,626C 'bypass':555C 'call':120C,146C,164C,211C,429C,486C 'cannot':320C 'caus':482C 'channel':226C,231C,238C,446C,580C,589C,596C,643C,657C 'chat':249C,445C 'citat':253C,314C,661C 'colon':431C 'computeronfir':660C 'concept':571C,650C 'configur':318C,480C 'confirm':335C 'consecutivedetailsgroup.svelte':497C 'contain':339C 'content':140C,206C,348C,462C,536C,568C,592C 'control':199C 'convinc':343C 'credit':641C 'cross':653C 'cross-us':652C 'decod':171C 'default':241C,270C,317C,336C,414C,577C 'deliveri':655C 'demonstr':223C 'detail':553C 'direct':658C 'distinguish':158C,517C 'document':257C,667C 'download':610C 'element':180C,508C 'elev':265C 'emb':121C,155C,212C,272C,405C,468C,487C,500C 'enabl':187C,233C,237C,581C 'entir':557C 'everi':195C,396C,420C,563C 'execut':131C,297C,341C,394C,524C,621C 'explicit':456C 'featur':232C,262C 'fenc':432C 'fix':398C,399C 'flag':263C,413C 'forward':418C 'fullheightifram':510C 'fulli':473C 'gadget':244C 'gain':362C 'gate':203C 'generat':161C 'group':547C 'guard':541C 'hijack':385C 'html':614C 'ifram':184C,273C,304C,469C,561C,599C,636C 'iframesandboxallowsameorigin':359C 'impact':293C,382C 'in-app':344C 'includ':424C 'inject':286C,295C,619C 'input':170C 'insid':350C 'instanc':220C 'interfac':352C 'issu':476C 'javascript':133C 'json':174C 'json-pars':173C 'kadirarslan':642C 'knowledg':665C 'knowledge-bas':664C 'later':539C 'live':489C 'localstorag':372C 'longer':465C 'main':248C 'main-chat':247C 'make':328C 'markdown':124C,149C,421C,493C 'messag':227C,251C,310C,447C,535C,590C,631C,644C,659C 'miss':198C 'mount':178C,506C 'need':259C 'never':516C 'non':584C 'non-admin':583C 'null':301C,627C 'null-origin':300C 'one':598C 'opaqu':291C 'open':312C,594C 'oper':355C 'opt':410C,437C 'opt-in':409C 'origin':283C,292C,302C,331C,366C,628C,645C 'output':165C 'pars':151C,175C,528C 'pass':454C 'path':213C,423C,548C,674C 'payload':387C 'phish':347C 'pipelin':525C 'popup':607C 'post':587C 'pr':403C 'precondit':214C 'preview':254C,662C 'primari':222C 'primit':337C 'produc':519C 'proof':569C,648C 'rais':380C 'ran':190C 're':393C 're-execut':392C 'reach':246C,466C,559C 'read':321C,371C,450C,498C 'read-on':449C 'render':125C,150C,192C,349C,406C,422C,494C,515C,566C,597C,634C 'report':646C 'reproduc':572C 'request':333C 'requir':229C,268C 'resolv':474C 'respons':436C 'retriev':256C 'role':266C 'root':481C 'run':288C,640C 'same-origin':329C 'sandbox':183C,275C,303C,361C,601C 'script':186C,278C,287C,296C,340C,369C,604C,620C,639C 'send':139C 'separ':204C 'server':160C 'server-gener':159C 'session':325C,373C,384C 'set':578C 'shape':141C 'share':492C 'singl':551C 'sink':488C 'special':261C 'srcdoc':616C 'standalon':426C,552C,672C 'standalone-block':671C 'stock':574C 'store':112C,389C 'summari':126C 'surfac':224C,564C 'time':193C 'token':326C,374C,504C,518C,527C 'tool':119C,145C,163C,210C,428C,485C,523C 'tool-cal':118C,144C,162C,209C,427C,484C 'tool-execut':522C 'toolcalldisplay.svelte':495C 'true':513C 'trust':202C 'turn':357C 'ungat':670C 'upgrad':470C 'user':116C,129C,136C,168C,205C,250C,460C,533C,567C,654C 'user-author':115C,167C,459C,532C 'via':114C 'victim':379C 'view':308C,397C,453C 'viewer':196C,323C,442C,624C 'whose':591C 'without':157C,279C 'xss':113C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-09-27T19:27:08+00:00","kev":null,"cvss_vector":"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","cvss_by":"disclosure@vulncheck.com","poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-9wj4-mcm3-ppj6","url":"https://github.com/open-webui/open-webui/security/advisories/GHSA-9wj4-mcm3-ppj6","severity":"medium","published_at":"2026-09-27T19:27:08+00:00","modified_at":"2026-10-28T20:47:18+00:00","first_seen_at":"2026-11-09T22:53:26+00:00","fetched_at":"2026-11-09T22:53:26+00:00","note":null},{"source":"nvd","external_id":"CVE-2026-109300","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-109300","severity":null,"published_at":"2026-10-12T17:17:23+00:00","modified_at":"2026-10-15T15:55:45+00:00","first_seen_at":"2026-11-09T23:10:12+00:00","fetched_at":"2026-11-09T23:10:12+00:00","note":null}],"documents":[{"id":110645,"url":"https://github.com/open-webui/open-webui/security/advisories/GHSA-9wj4-mcm3-ppj6","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa-repo","publisher":"vendor","text":null,"published_at":"2026-09-27T19:27:08+00:00","relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"},{"id":111044,"url":"https://www.vulncheck.com/advisories/open-webui-0.6.31-before-0.11.4-stored-xss-via-tool-call-embeds","title":"Third-party advisory: www.vulncheck.com","kind":"advisory","source":"nvd","publisher":"research","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Third-party advisory: www.vulncheck.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}