diff --git a/backend/open_webui/routers/models.py b/backend/open_webui/routers/models.py index 75ee4e723b..75c37b0eb9 100644 --- a/backend/open_webui/routers/models.py +++ b/backend/open_webui/routers/models.py @@ -60,6 +60,9 @@ def _safe_static_redirect_path(url: str) -> str | None: if decoded == path: break path = decoded + # Fail closed: a value still encoded after the cap would be decoded further downstream. + if unquote(path) != path: + return None if '\x00' in path or '\\' in path: return None if not path.startswith('/'): diff --git a/backend/open_webui/routers/terminals.py b/backend/open_webui/routers/terminals.py index 6a942cf9b2..4c71322bfb 100644 --- a/backend/open_webui/routers/terminals.py +++ b/backend/open_webui/routers/terminals.py @@ -43,6 +43,9 @@ def _sanitize_proxy_path(path: str) -> str | None: if once == decoded: break decoded = once + # Fail closed: still encoded after the cap means the upstream would decode further into traversal. + if unquote(decoded) != decoded: + return None had_trailing_slash = decoded.endswith('/') normalized = posixpath.normpath(decoded) # Remove any leading slashes that would reset the base