CSIRTS // UNIFIED SECURITY ADVISORY FEEDSYS ● ONLINE · POWERED BY INTELFUSIONS.COM

GHSA-frvj-c5qp-xj4w: open-webui terminal proxy path traversal guard bypass via 9x encoded traversal

highCVSS 7.7CVE-2026-59221
AI assistance was used to help inspect the code and prepare this report. Summary The fix for GHSA-r2wg-2mcr-66rv is incomplete in v0.9.6 and current main. backend/open_webui/routers/terminals.py documents _sanitize_proxy_path() as decoding until stable, but the implementation stops after 8 unquote() passes. A 9x percent-encoded ../... path parameter remains once-encoded after the loop, passes the posixpath.normpath() and cleaned.startswith('..') checks, and is forwarded to the configured terminal server. The upstream server then receives a decoded traversal path such as /base/../admin/system. Impact A user who has access to an admin-configured terminal connection can bypass the terminal proxy path traversal guard and cause Open WebUI to forward requests with the configured terminal credentials and X-User-Id header to paths outside the intended normalized proxy path. For orchestrator-backed terminal connections the same sanitized path is placed under /p/{policy_id}/{safe_path}, so the bypass can also target sibling or parent routes after upstream decoding. This is a bypass of the same terminal proxy boundary covered by GHSA-r2wg-2mcr-66rv. This does not require adding a malicious terminal server or convincing an administrator to weaken settings. The attacker only needs normal access to an existing configured terminal connection. Reproduction The following standalone Python script mirrors the current sanitizer and uses a local aiohttp server as the terminal-server canary. It shows that 8x encoding is rejected but 9x encoding is accepted and forwarded as a traversal after the upstream framework decodes the path. import asyncio, posixpath from urllib.parse import unquote from aiohttp import web, ClientSession, ClientTimeout def sanitize(path): decoded = path for _ in range(8): once = unquote(decoded) if once == decoded: break decoded = once cleaned = posixpath.normpath(decoded).lstrip('/') if cleaned.startswith('..') or cleaned == '.': return None return cleane

Details

Source
GitHub Security Advisories (INTL · database · site)
Severity
high — CVSS 7.7
Published
2026-07-24
Last updated
2026-07-24
Exploitation
Not in CISA KEV at last sync

Original advisory: https://github.com/advisories/GHSA-frvj-c5qp-xj4w

Exploitation outlook

EPSS (FIRST.org) estimates each CVE’s probability of exploitation in the next 30 days — here is the CSIRTS.com read on those numbers.

Referenced CVEs

CVECSIRTS overviewExternal
CVE-2026-59221coverage & exploitation statusNVD · CVE.org

Same CVEs, other sources

How other CERTs, PSIRTs and databases cover the vulnerabilities in this advisory.

More from GitHub Security Advisories