GHSA-jrfp-m64g-pcwv CVE-2026-54018 PYSEC-2026-2743
Open WebUI: SSRF Protection Bypass in Playwright Web Loader via HTTP Redirects
- Severity
- 7.7 / 10
- High · CVSS 3.1
- Exploit chance (EPSS)
- 0.39%
- Chance of exploitation in the next 30 days. Higher than 32.65% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Weakness
- CWE-918 Server-Side Request Forgery (SSRF)
- Fix
0.9.6- Upgrade open-webui to this version or later
Description
Summary
The SafePlaywrightURLLoader implements a validate_url function to prevent SSRF attacks by checking the IP address of the user-provided URL. However, this validation is performed only on the initial URL.
Since Playwright automatically follows HTTP redirects (301/302) by default, an attacker can bypass the validation by providing a safe URL that redirects to a restricted internal network address (e.g., localhost, Docker container network, or Cloud Metadata).
This allows the application to access internal services despite ENABLE_RAG_LOCAL_WEB_FETCH being set to False
Details
Root Cause
The application validates the initial user-provided URL using self._safe_process_url_sync(url). This correctly resolves the domain and ensures it does not point to a private IP.
The application then calls page.goto(url). By default, Playwright automatically follows HTTP redirects (301/302).
The Bypass: If the destination server returns a redirect to an internal IP (e.g., 127.0.0.1 or 169.254.169.254), the browser follows it without re-validating the new destination. The initial validation is bypassed because it only checked the first URL, not the entire redirect chain.
for url in self.urls:
try:
self._safe_process_url_sync(url)
page = browser.new_page()
response = page.goto(url, timeout=self.playwright_timeout) #this
if response is None:
raise ValueError(...)
text = self.evaluator.evaluate(page, browser, response)
PoC
(This PoC uses Docker to easily demonstrate internal network access (accessing a container by service name). However, the vulnerability is NOT tied to Docker.)
- Ensure the Open WebUI is configured with the following environment variables. The vulnerability is specific to the Playwright engine.
- ENABLE_RAG_LOCAL_WEB_FETCH=False (Default)
- RAG_WEB_LOADER_ENGINE=playwright
- Setup and run attack server
- In Open WebUI, use the "Web Search" or "URL Loader" feature.
- Input the attacker's URL (e.g., http://attacker-ip/).
# attack_server.py
from flask import Flask, redirect
app = Flask(__name__)
@app.route('/')
def attack():
# Redirect to the Open WebUI container's internal port
return redirect("http://open-webui:8080/api/version", code=302)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
<img width="580" height="192" alt="image" src="https://github.com/user-attachments/assets/4600dbb5-a81d-4e58-b787-afe04fe59d6e" />
The Playwright browser follows the redirect to the internal address (http://open-webui:8080/api/version)
Impact
- Cloud Environments: Access to Instance Metadata Service (IMDS) to steal cloud credentials.
- Intranet/On-Premise: Scanning internal networks and accessing unauthenticated internal tools.
- Container Environments: Accessing other containers within the same network.
Recommended Patch
implement a request interceptor using Playwright's page.route. This ensures all requests, including redirects, are validated before connection.
apply the following logic to both lazy_load and alazy_load methods:
# async context
async def intercept_route(route):
try:
await run_in_threadpool(validate_url, route.request.url)
await route.continue_()
except Exception:
await route.abort()
await page.route("**/*", intercept_route)
response = await page.goto(url, timeout=self.playwright_timeout)
Affected versions
PyPI
| Package | Vulnerable | Fixed in |
|---|---|---|
| open-webui | < 0.9.6 |
0.9.6 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
open-webui PyPI → 0.9.6
- pip
pip install --upgrade "open-webui>=0.9.6"- poetry
poetry add "open-webui>=0.9.6"- uv
uv add "open-webui>=0.9.6"
Severity breakdown
CVSS 3.1 7.7
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
- Attack vector
- Network
- Attack complexity
- Low
- Privileges required
- Low
- User interaction
- None
- Scope
- Changed
- Confidentiality
- High
- Integrity
- None
- Availability
- None
Weakness
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.
References
Advisories
Packages
Other links
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GHSA-wvm9-9g5j-623f Open WebUI: Users denied by the OAuth role policy can still sign in via token exchange | Medium | Also affects open-webui |
| GHSA-4qg5-cxx4-g927 Open WebUI: Users denied by the OAuth domain allowlist or role policy can still sign in via token exchange | Medium | Also affects open-webui |
| GHSA-jqhh-cjmq-vmv6 Open WebUI: Any authenticated user can hang the server via a cyclic chat message history | Medium | Also affects open-webui |
| GHSA-5x7x-4c3c-qf5w Open WebUI: Server-side fetches reach blocked and internal hosts via unvalidated HTTP redirect targets | Medium | Also affects open-webui |
| GHSA-3cgp-3cqx-j8w2 Open WebUI: Any authenticated user can hang the server via message deletion in a cyclic chat tree | Medium | Also affects open-webui |
| GHSA-34r3-9m95-vq73 Open WebUI: Any authenticated user can reach the Azure platform channel via server-side web fetch | High | Also affects open-webui |
| GHSA-2724-6cpj-gf3v Open WebUI: Non-admin users can delete admin-owned external knowledge connections via knowledge base deletion | High | Also affects open-webui |
| GHSA-3pf7-q2g3-wj28 Open WebUI: Any authenticated user can inject chats into another user's folder via chat completions | Medium | Also affects open-webui |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor