From b40b6fd698569e623137080ce94301ecf87e0355 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 27 Jul 2026 07:01:10 +0200 Subject: [PATCH] fix: reject backslash in the terminal proxy path sanitizer (#27198) _sanitize_proxy_path decodes the path and then relies on posixpath.normpath plus a leading '..' check. posixpath splits on '/' only, so a backslash run is treated as part of a single path component: 'foo/..\..\etc' normalizes to itself, does not start with '..' and is forwarded unchanged, reaching the upstream as '/foo/..%5C..%5Cetc'. An upstream that treats the backslash as a separator would resolve those '..' sequences. Reject any path containing a backslash after decoding, matching the existing fail-closed behaviour for paths that are still encoded past the decode cap. A backslash is not meaningful in the upstream API paths this route proxies, so legitimate requests are unaffected. Co-authored-by: babakizo420 --- backend/open_webui/routers/terminals.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/open_webui/routers/terminals.py b/backend/open_webui/routers/terminals.py index 441b53598c..191fb96a1f 100644 --- a/backend/open_webui/routers/terminals.py +++ b/backend/open_webui/routers/terminals.py @@ -49,6 +49,10 @@ def _sanitize_proxy_path(path: str) -> str | None: # Fail closed: still encoded after the cap means the upstream would decode further into traversal. if unquote(decoded) != decoded: return None + # posixpath splits on '/' only, so 'a/..\..\b' survives normpath as one component. + # Upstreams that treat '\' as a separator would resolve it, so reject outright. + if '\\' in decoded: + return None had_trailing_slash = decoded.endswith('/') normalized = posixpath.normpath(decoded) # Remove any leading slashes that would reset the base