{"id":"CVE-2026-109291","kind":"vulnerability","aliases":["CVE-2026-109291","GHSA-qpqv-xwg8-cqpj"],"related":[],"title":"Viewer session token theft via a script link in a shared chat's citation","description":"# Viewer session token theft via a script link in a shared chat's citation\r\n\r\n## Summary\r\nAny authenticated user can store a `javascript:` URL in the `embed_url` field of a chat citation and share that chat with another user. When the second user opens the shared chat and clicks the citation, the URL is passed straight to `window.open`, executing attacker script in the Open WebUI origin. The frontend never checks the URL scheme before opening it, so the attacker's script runs with the victim's session and can read `localStorage.token` and act as the victim.\r\n\r\n## Preconditions\r\nDefault configuration, fresh database, no special settings. The attacker is any authenticated user who can create and share a chat (no admin rights, no `workspace.*` permission). The victim is any user who opens the shared read-only chat (`/s/{share_id}`), expands the sources, and clicks the malicious citation. The `embed_url` value is set by editing the attacker's own chat through the normal chat update API, which stores the attacker-controlled citation structure.\r\n\r\n## Impact\r\nScript executes in the application origin as the victim, so the attacker can exfiltrate `localStorage.token` (the JWT used for every API call) and then act with the victim's permissions, including reading the victim's private chats. Exploitation requires the victim to click the citation in the shared chat. If the victim is an administrator, the account compromise extends to admin capabilities. Only the citation-embed click path is affected; citations whose `embed_url` is a normal http/https link are unaffected.\r\n\r\n## Fix\r\nFixed in 0.11.4 by PR #29701. The citation click handler now requires the `embed_url` to be an `http`/`https` URL (or protocol-relative) before it is opened or handed to the embed panel; any other value, including a `javascript:` URL, falls back to the citation modal, which renders the source safely. Upgrading to 0.11.4 fully resolves the issue with no further configuration.\r\n\r\n## Root cause\r\n`src/lib/components/chat/Messages/Citations.svelte` (`showSourceModal`) read `citations[index].source.embed_url` and, when the chat is read-only, called `window.open(embedUrl, '_blank')` directly. The value comes from the stored chat, which a user fully controls through the chat update API, and no URL-scheme validation stood between the stored value and the sink. The read-only `window.open` branch shipped from 0.6.33 onward, so every build from 0.6.33 through 0.11.3 carried the code.\r\n\r\n## Proof of concept\r\nThe reporter reproduced with two normal accounts on a default 0.11.3 instance: the attacker stored a citation with `embed_url` set to a `javascript:` payload that fetched `localStorage.token` to a listener, shared the chat with the victim, and on the victim clicking the citation the token was exfiltrated and then used to read a private victim chat that the attacker account could not access directly. Independently confirmed in Chromium that `window.open` with a `javascript:` URL and a `_blank` target runs in the opening page's origin and can read and send its `localStorage.token`. On 0.11.4 the guard rejects `javascript:` and `data:` values and admits only http, https and protocol-relative URLs to that path.\r\n\r\n## Credits\r\nReported by @zyakir13. Fix by @Classic298.","summary":"Open WebUI's citation click handler opens a stored embed_url without checking its scheme, so a javascript: URL runs script in the app's origin. A user who opens a shared chat and clicks the malicious citation has their session token readable by the attacker, allowing account takeover.","severity":"high","cvss":8.5,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"open-webui","fixed":["0.11.4"],"affected":">= 0.6.33, < 0.11.4","ecosystem":"pypi"}],"ecosystems":["pypi"],"tags":["ai-tooling","cwe-79","open-webui","python","self-hosted"],"not_affected_if":["no-shared-chats","version-0.11.4-or-later"],"how_to_check":"- Check the installed version: `pip show open-webui` and confirm it is below `0.11.4`.\n- Affected range is `>= 0.6.33` and `< 0.11.4`.\n- Only the citation embed click path is affected; default configuration with no special settings is affected.","fix":"- Upgrade `open-webui` to `0.11.4` (fixed by PR #29701). The sources state no further configuration is needed.","status":"open","published_at":"2026-09-27T19:45:25+00:00","first_seen_at":"2026-11-09T22:53:27+00:00","triaged_at":"2026-11-09T22:59:30+00:00","updated_at":"2026-11-09T23:10:12+00:00","category":"ai-tooling","confidence":0.9,"triage":{"at":"2026-11-09T22:59:30Z","model":"claude-haiku-5-5","output":{"fix":"- Upgrade `open-webui` to `0.11.4` (fixed by PR #29701). The sources state no further configuration is needed.","reach":"internet","title":"Open WebUI: shared chat citation link runs script and steals session token","impact":"high","summary":"Open WebUI's citation click handler opens a stored embed_url without checking its scheme, so a javascript: URL runs script in the app's origin. A user who opens a shared chat and clicks the malicious citation has their session token readable by the attacker, allowing account takeover.","audience":"businesses","category":"ai-tooling","nicknames":[],"who_cares":["open-webui","self-hosted","python"],"confidence":0.9,"fix_status":"available","needs_auth":"yes","worst_case":"Attacker runs script as victim, steals session token, takes over account","analyst_note":"","how_to_check":"- Check the installed version: `pip show open-webui` and confirm it is below `0.11.4`.\n- Affected range is `>= 0.6.33` and `< 0.11.4`.\n- Only the citation embed click path is affected; default configuration with no special settings is affected.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["version-0.11.4-or-later","no-shared-chats"],"who_is_affected":"Any Open WebUI deployment from 0.6.33 through 0.11.3 with default settings is exposed, because any authenticated user can share a chat containing the malicious citation with another user. Exposure requires a victim to open the shared chat and click the citation. Instances on 0.11.4 or later are not affected.","user_interaction":"yes","product_ecosystem":"","needs_special_setup":"no","severity_if_unknown":"high"},"cost_usd":0.000858,"input_tokens":5602,"output_tokens":596,"severity_before":"high"},"analyst_status":null,"analyst_note":null,"search":"'-109291':17A,25A '-2026':16A,24A '-79':33B '/s':226C '0.11.3':481C,498C '0.11.4':350C,403C,582C '0.6.33':473C,479C '29701':353C 'access':551C 'account':88B,321C,494C,548C 'act':182C,289C 'admin':208C,325C 'administr':319C 'admit':591C 'affect':335C 'ai':30B 'ai-tool':29B 'allow':87B 'anoth':127C 'api':255C,285C,450C 'app':64B 'applic':269C 'attack':86B,149C,168C,195C,246C,260C,276C,501C,547C 'attacker-control':259C 'authent':106C,198C 'back':391C 'blank':432C,565C 'branch':470C 'build':477C 'call':286C,429C 'capabl':326C 'carri':482C 'caus':413C 'chat':12A,73B,101C,120C,125C,136C,206C,225C,249C,253C,301C,313C,424C,440C,448C,521C,544C 'check':53B,159C 'chromium':556C 'citat':14A,44B,78B,103C,121C,140C,236C,262C,309C,330C,336C,355C,394C,417C,504C,531C 'citation-emb':329C 'classic298':609C 'click':45B,75B,138C,233C,307C,332C,356C,529C 'code':484C 'come':436C 'compromis':322C 'concept':487C 'configur':188C,411C 'confirm':554C 'control':261C,445C 'could':549C 'cqpj':22A 'creat':202C 'credit':603C 'cve':15A,23A 'cwe':32B 'data':588C 'databas':190C 'default':187C,497C 'direct':433C,552C 'edit':244C 'emb':50B,115C,238C,331C,338C,361C,381C,506C 'embedurl':431C 'everi':284C,476C 'execut':148C,266C 'exfiltr':278C,535C 'expand':229C 'exploit':302C 'extend':323C 'fall':390C 'fetch':514C 'field':117C 'fix':347C,348C,607C 'fresh':189C 'frontend':157C 'fulli':404C,444C 'ghsa':19A 'ghsa-qpqv-xwg8-cqpj':18A 'guard':584C 'hand':378C 'handler':46B,357C 'host':40B 'http':366C,593C 'http/https':343C 'https':367C,594C 'id':228C 'impact':264C 'includ':295C,386C 'independ':553C 'index':418C 'instanc':499C 'issu':407C 'javascript':58B,111C,388C,511C,561C,586C 'jwt':281C 'link':8A,97C,344C 'listen':518C 'localstorage.token':180C,279C,515C,580C 'malici':77B,235C 'modal':395C 'never':158C 'normal':252C,342C,493C 'onward':474C 'open':27A,35B,41B,47B,70B,133C,153C,164C,219C,376C,570C 'open-webui':26A,34B 'origin':66B,155C,270C,573C 'page':571C 'panel':382C 'pass':144C 'path':333C,602C 'payload':512C 'permiss':212C,294C 'pr':352C 'precondit':186C 'privat':300C,542C 'proof':485C 'protocol':371C,597C 'protocol-rel':370C,596C 'python':37B 'qpqv':20A 'read':179C,223C,296C,416C,427C,467C,540C,576C 'read-on':222C,426C,466C 'readabl':83B 'reject':585C 'relat':372C,598C 'render':397C 'report':489C,604C 'reproduc':490C 'requir':303C,359C 'resolv':405C 'right':209C 'root':412C 'run':60B,171C,567C 'safe':400C 'scheme':55B,162C,455C 'script':7A,61B,96C,150C,170C,265C 'second':131C 'self':39B 'self-host':38B 'send':578C 'session':2A,81B,91C,176C 'set':193C,242C,508C 'share':11A,72B,100C,123C,135C,204C,221C,227C,312C,519C 'ship':471C 'showsourcemod':415C 'sink':464C 'sourc':231C,399C 'source.embed':419C 'special':192C 'src/lib/components/chat/messages/citations.svelte':414C 'stood':457C 'store':49B,109C,257C,439C,460C,502C 'straight':145C 'structur':263C 'summari':104C 'takeov':89B 'target':566C 'theft':4A,93C 'token':3A,82B,92C,533C 'tool':31B 'two':492C 'unaffect':346C 'updat':254C,449C 'upgrad':401C 'url':51B,59B,112C,116C,142C,161C,239C,339C,362C,368C,389C,420C,454C,507C,562C,599C 'url-schem':453C 'use':282C,538C 'user':68B,107C,128C,132C,199C,217C,443C 'valid':456C 'valu':240C,385C,435C,461C,589C 'via':5A,94C 'victim':174C,185C,214C,273C,292C,298C,305C,316C,524C,528C,543C 'viewer':1A,90C 'webui':28A,36B,42B,154C 'whose':337C 'window.open':147C,430C,469C,558C 'without':52B 'workspac':211C 'xwg8':21A 'zyakir13':606C","nicknames":[],"mitigations":[],"who_affected":"Any Open WebUI deployment from 0.6.33 through 0.11.3 with default settings is exposed, because any authenticated user can share a chat containing the malicious citation with another user. Exposure requires a victim to open the shared chat and click the citation. Instances on 0.11.4 or later are not affected.","tier":"B","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"businesses","plain_action":null,"pkeys":["openwebui"],"ptokens":["open","webui"],"labels":["aitooling","cwe79","high","openwebui","pypi","python","selfhosted"],"campaign_type":null,"search_a":"'-109291':17A,25A '-2026':16A,24A 'chat':12A 'citat':14A 'cqpj':22A 'cve':15A,23A 'ghsa':19A 'ghsa-qpqv-xwg8-cqpj':18A 'link':8A 'open':27A 'open-webui':26A 'qpqv':20A 'script':7A 'session':2A 'share':11A 'theft':4A 'token':3A 'via':5A 'viewer':1A 'webui':28A 'xwg8':21A","search_b":"'-79':33B 'account':88B 'ai':30B 'ai-tool':29B 'allow':87B 'app':64B 'attack':86B 'chat':73B 'check':53B 'citat':44B,78B 'click':45B,75B 'cwe':32B 'emb':50B 'handler':46B 'host':40B 'javascript':58B 'malici':77B 'open':35B,41B,47B,70B 'open-webui':34B 'origin':66B 'python':37B 'readabl':83B 'run':60B 'scheme':55B 'script':61B 'self':39B 'self-host':38B 'session':81B 'share':72B 'store':49B 'takeov':89B 'token':82B 'tool':31B 'url':51B,59B 'user':68B 'webui':36B,42B 'without':52B","search_c":"'/s':226C '0.11.3':481C,498C '0.11.4':350C,403C,582C '0.6.33':473C,479C '29701':353C 'access':551C 'account':321C,494C,548C 'act':182C,289C 'admin':208C,325C 'administr':319C 'admit':591C 'affect':335C 'anoth':127C 'api':255C,285C,450C 'applic':269C 'attack':149C,168C,195C,246C,260C,276C,501C,547C 'attacker-control':259C 'authent':106C,198C 'back':391C 'blank':432C,565C 'branch':470C 'build':477C 'call':286C,429C 'capabl':326C 'carri':482C 'caus':413C 'chat':101C,120C,125C,136C,206C,225C,249C,253C,301C,313C,424C,440C,448C,521C,544C 'check':159C 'chromium':556C 'citat':103C,121C,140C,236C,262C,309C,330C,336C,355C,394C,417C,504C,531C 'citation-emb':329C 'classic298':609C 'click':138C,233C,307C,332C,356C,529C 'code':484C 'come':436C 'compromis':322C 'concept':487C 'configur':188C,411C 'confirm':554C 'control':261C,445C 'could':549C 'creat':202C 'credit':603C 'data':588C 'databas':190C 'default':187C,497C 'direct':433C,552C 'edit':244C 'emb':115C,238C,331C,338C,361C,381C,506C 'embedurl':431C 'everi':284C,476C 'execut':148C,266C 'exfiltr':278C,535C 'expand':229C 'exploit':302C 'extend':323C 'fall':390C 'fetch':514C 'field':117C 'fix':347C,348C,607C 'fresh':189C 'frontend':157C 'fulli':404C,444C 'guard':584C 'hand':378C 'handler':357C 'http':366C,593C 'http/https':343C 'https':367C,594C 'id':228C 'impact':264C 'includ':295C,386C 'independ':553C 'index':418C 'instanc':499C 'issu':407C 'javascript':111C,388C,511C,561C,586C 'jwt':281C 'link':97C,344C 'listen':518C 'localstorage.token':180C,279C,515C,580C 'malici':235C 'modal':395C 'never':158C 'normal':252C,342C,493C 'onward':474C 'open':133C,153C,164C,219C,376C,570C 'origin':155C,270C,573C 'page':571C 'panel':382C 'pass':144C 'path':333C,602C 'payload':512C 'permiss':212C,294C 'pr':352C 'precondit':186C 'privat':300C,542C 'proof':485C 'protocol':371C,597C 'protocol-rel':370C,596C 'read':179C,223C,296C,416C,427C,467C,540C,576C 'read-on':222C,426C,466C 'reject':585C 'relat':372C,598C 'render':397C 'report':489C,604C 'reproduc':490C 'requir':303C,359C 'resolv':405C 'right':209C 'root':412C 'run':171C,567C 'safe':400C 'scheme':162C,455C 'script':96C,150C,170C,265C 'second':131C 'send':578C 'session':91C,176C 'set':193C,242C,508C 'share':100C,123C,135C,204C,221C,227C,312C,519C 'ship':471C 'showsourcemod':415C 'sink':464C 'sourc':231C,399C 'source.embed':419C 'special':192C 'src/lib/components/chat/messages/citations.svelte':414C 'stood':457C 'store':109C,257C,439C,460C,502C 'straight':145C 'structur':263C 'summari':104C 'target':566C 'theft':93C 'token':92C,533C 'two':492C 'unaffect':346C 'updat':254C,449C 'upgrad':401C 'url':112C,116C,142C,161C,239C,339C,362C,368C,389C,420C,454C,507C,562C,599C 'url-schem':453C 'use':282C,538C 'user':107C,128C,132C,199C,217C,443C 'valid':456C 'valu':240C,385C,435C,461C,589C 'via':94C 'victim':174C,185C,214C,273C,292C,298C,305C,316C,524C,528C,543C 'viewer':90C 'webui':154C 'whose':337C 'window.open':147C,430C,469C,558C 'workspac':211C 'zyakir13':606C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-09-27T19:45:25+00:00","kev":null,"cvss_vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/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-qpqv-xwg8-cqpj","url":"https://github.com/open-webui/open-webui/security/advisories/GHSA-qpqv-xwg8-cqpj","severity":"high","published_at":"2026-09-27T19:45:25+00:00","modified_at":"2026-10-28T20:47:03+00:00","first_seen_at":"2026-11-09T22:53:27+00:00","fetched_at":"2026-11-09T22:53:27+00:00","note":null},{"source":"nvd","external_id":"CVE-2026-109291","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-109291","severity":null,"published_at":"2026-10-12T17:17:22+00:00","modified_at":"2026-10-18T12:17:04+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":110652,"url":"https://github.com/open-webui/open-webui/security/advisories/GHSA-qpqv-xwg8-cqpj","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa-repo","publisher":"vendor","text":null,"published_at":"2026-09-27T19:45:25+00:00","relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"},{"id":111028,"url":"https://www.vulncheck.com/advisories/open-webui-0.6.33-before-0.11.4-stored-xss-via-citation-embed-url","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"}