Skip to content

Open WebUI: SSRF Protection Bypass in Playwright Web Loader via HTTP Redirects

High severity GitHub Reviewed Published Jun 11, 2026 in open-webui/open-webui • Updated Jun 17, 2026

Package

pip open-webui (pip)

Affected versions

<= 0.9.5

Patched versions

0.9.6

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.)

  1. Ensure the Open WebUI is configured with the following environment variables. The vulnerability is specific to the Playwright engine.
  2. ENABLE_RAG_LOCAL_WEB_FETCH=False (Default)
  3. RAG_WEB_LOADER_ENGINE=playwright
  4. Setup and run attack server
  5. In Open WebUI, use the "Web Search" or "URL Loader" feature.
  6. 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)

image

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)

References

@doge-woof doge-woof published to open-webui/open-webui Jun 11, 2026
Published to the GitHub Advisory Database Jun 17, 2026
Reviewed Jun 17, 2026
Last updated Jun 17, 2026

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
Low
User interaction
None
Scope
Changed
Confidentiality
High
Integrity
None
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N

EPSS score

Exploit Prediction Scoring System (EPSS)

This score estimates the probability of this vulnerability being exploited within the next 30 days. Data provided by FIRST.
(9th percentile)

Weaknesses

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. Learn more on MITRE.

CVE ID

CVE-2026-54018

GHSA ID

GHSA-jrfp-m64g-pcwv

Source code

Credits

Loading Checking history
See something to contribute? Suggest improvements for this vulnerability.