CVE-2026-87996: Open WebUI: SSRF into internal services via DNS rebinding in the Playwright web loader
Open WebUI's Playwright web loader checks a URL's address and then lets the browser resolve the hostname again, so DNS rebinding sends the request to internal services. An authenticated user can read cloud metadata and other internal HTTP responses. Affected: 0.9.6 up to 0.11.1, with `WEB_LOADER_ENGINE=playwright`. Fixed in 0.11.1.
Published Sep 10, 2026 · Analysis Oct 23, 2026
What an attacker can do
SafePlaywrightURLLoader in backend/open_webui/retrieval/web/utils.py resolves the hostname in Python and checks it. It then gives the request to the browser, which resolves the name again on its own, and that answer is never checked. An attacker who runs the authoritative DNS for a hostname they submit can answer the first lookup with a public address and the second with an internal one. No timing race is needed. Playwright's request API cannot pin a connection, so the protection used on the other fetch paths could not apply.
The attacker needs any authenticated account that can submit a URL for ingestion or trigger a web search, plus a short-TTL DNS name they control. The response body returns through the page, and the loader hands it back as the document, so it lands in the user's search or ingestion result. The target can be cloud instance metadata, loopback admin APIs, or other internal services the browser can reach. The intercepted request forwards the original method and headers, so header-gated metadata endpoints are reachable. On a host with IMDSv1 reachable, that is enough to take instance IAM credentials.
This is a read primitive. The advisory demonstrated no change to Open WebUI data and no availability impact. Deployments on the default web loader are not affected.
Who is affected
Affected: open-webui from 0.9.6 up to but not including 0.11.1, when WEB_LOADER_ENGINE=playwright and a Playwright browser is reachable, locally or through PLAYWRIGHT_WS_URL. Check:
pip show open-webuiA browser with no network route to internal addresses has nothing to lose here.
open-webui
- Ecosystem
- PyPI
- Affected
- >= 0.9.6, < 0.11.1
- Fixed in
- 0.11.1
- Check
pip show open-webui
How to fix it
Upgrade to Open WebUI 0.11.1 (pull request 28634). No configuration change is needed.
pip install --upgrade "open-webui>=0.11.1"The interceptor now issues the request from the SSRF-safe HTTP client, which resolves the hostname once, connects to that same validated address and re-validates every redirect hop, then fulfils the browser with the response. Until you upgrade, switch WEB_LOADER_ENGINE back to the default loader and block the browser's route to metadata and internal ranges.
How to tell if you were hit
Review egress and internal service logs for requests from the Playwright browser host to 169.254.169.254, loopback or private ranges. Check DNS logs for submitted hostnames that returned a public address and then an internal one within seconds. Look at web-search and ingestion results for content that looks like metadata or internal admin pages. If IMDSv1 was reachable, rotate the instance's IAM credentials.
Original advisory
From the GitHub Advisory Database (CC BY 4.0).
Summary
With the Playwright web loader enabled, Open WebUI checks the address behind a user-submitted URL before allowing the request, then handed the request to the browser to perform. The browser resolved the hostname a second time, on its own, and that answer was never checked. An attacker who controls the authoritative DNS for a hostname they submit can answer the first lookup with a public address and the second with an internal one, so the browser connects to an address the check exists to block. The connection-layer pinning that protects the other fetch paths could not apply here, because the request ran inside the browser rather than through our own HTTP clients.
Preconditions
WEB_LOADER_ENGINE=playwright. This is not the default, and deployments on the default web loader are unaffected.- A reachable Playwright browser, either local or via
PLAYWRIGHT_WS_URL. - Any authenticated user who can submit a URL for ingestion or trigger a web search. No administrator role is required.
- Control of the authoritative DNS for a hostname the attacker submits, serving a short TTL and alternating answers. No timing race is needed, because the two lookups are separate queries the attacker answers differently.
- Internal services the browser process can actually reach. A deployment whose browser has no route to internal addresses loses nothing here.
Impact
An authenticated user can make the server read HTTP responses from addresses only it can reach: cloud instance metadata, loopback-bound admin APIs, and internal services on the same network. The response body is fulfilled back into the page, and the loader returns that page as the document, so the content lands in the web-search or ingestion result the user receives. On a cloud host with IMDSv1 reachable, that is enough to take instance IAM credentials.
Because the intercepted request forwards the original method and headers, a page the attacker controls can also drive requests that need a header or a non-GET method, which covers the header-gated metadata endpoints. This is a read primitive; no modification of Open WebUI data and no availability impact was demonstrated. Deployments on the default web loader are not affected at all.
Fix
Fixed in 0.11.1 by commit 27402ff21 (#28634). The interceptor no longer asks the browser to perform the request. It issues the request from the SSRF-safe HTTP client instead, which resolves the hostname once and connects to that same validated address, re-validates every redirect hop, and then fulfils the browser with the response it received. Upgrading to 0.11.1 fully resolves this, and no configuration change is required.
Root cause
Affected component: SafePlaywrightURLLoader in backend/open_webui/retrieval/web/utils.py, in both the sync and async request interceptors. Affected setup: only builds running the Playwright loader engine.
The address check and the connection were performed by two different resolvers in two different processes. Validation resolved the hostname in Python and inspected the result, then the request was handed to the browser, which resolved the name again and connected to whatever it got. Playwright's request-fetch API offers no way to pin a connection to an already-validated address, so the fix that had been applied to the other fetch paths, resolving once and connecting to that same address, could not reach this one. The check was therefore an opinion about an earlier lookup rather than a constraint on the connection that followed.
Proof of concept
Reproduced against the real implementation: the validation and interception code was taken unmodified, with only the module-level configuration constants stubbed at their documented defaults, and driven against a real Chromium instance inside an unprivileged network namespace with an authoritative DNS server answering the first lookup public and the second internal. Instance metadata and a loopback service were both reached, with the response body returned through the page. A second run showed an attacker-controlled page driving the header-gated metadata sequence to completion. The path from the HTTP endpoint to the loader was traced in source rather than driven end to end.
Credits
- @baeseungwon1010 — identified that the address check and the browser's own resolution are two separate lookups, so the check cannot constrain where the browser connects.
Credited to baeseungwon1010, Classic298.
Questions
- Is the default web loader affected by CVE-2026-87996?
No. Only
WEB_LOADER_ENGINE=playwrightis affected.- Does the attacker need admin access?
No. Any authenticated user who can submit a URL for ingestion or trigger a web search can do it, plus control of a DNS name.
- What can be stolen?
Responses from addresses only the server can reach: cloud metadata, loopback admin APIs and internal services. On a cloud host with IMDSv1 reachable, instance IAM credentials.
References
How this page is made: the data panel comes from the GitHub Advisory Database, CISA’s KEV catalog, the NVD and FIRST EPSS, and updates twice a day. The analysis is written by an AI model from the sources listed above and checked by automated rules before it is published. Check versions against the vendor's advisory before you act. Methodology
More Open WebUI vulnerabilities
All Open WebUI entriesCVE-2026-87011
Open WebUI: Unauthenticated requests can stall the server via uncached OIDC fetches in back-channel logout
high7.5Sep 10, 2026CVE-2026-87012
Open WebUI: Any authenticated user can suppress calendar alerts instance-wide via a non-numeric alert value
medium4.3Sep 10, 2026CVE-2026-87013
Open WebUI: Any authenticated user can start a non-terminating request via a folder parent cycle
medium4.3Sep 10, 2026CVE-2026-87014
Open WebUI: Admin demoted through SSO role sync keeps read and write access to all users' notes
medium6.5Sep 10, 2026CVE-2026-87015
Open WebUI: A user's session cookies are sent to tool servers configured for bearer authentication
medium6.8Sep 10, 2026CVE-2026-87016
Open WebUI: Sign-in as another user via wildcard characters in the OAuth subject claim on SQLite
high8.1Sep 10, 2026
