From b0fa4384ea93685250f7599f311c93f60987cac4 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 1 Jun 2026 19:17:02 +0200 Subject: [PATCH] fix: cache path traversal via sibling-prefix bypass in serve_cache_file (#25086) serve_cache_file gated the resolved path with file_path.startswith(os.path.abspath(CACHE_DIR)) without a trailing os.sep, so any path resolving to a sibling whose name starts with the cache-dir basename (e.g. cache_backup, cached_models) passed the prefix check. Authenticated users could read files from such siblings via /cache/..//. Appending os.sep to the prefix closes the bypass; deep traversal and absolute paths were already correctly blocked. Co-authored-by: Claude Opus 4.7 (1M context) --- backend/open_webui/main.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 2c1cbf227a..6250dd947e 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -2935,7 +2935,10 @@ async def serve_cache_file( XSS from user-generated HTML stored in the cache directory. """ file_path = os.path.abspath(os.path.join(CACHE_DIR, path)) - if not file_path.startswith(os.path.abspath(CACHE_DIR)): + # trailing os.sep is required: without it, a path resolving to a sibling + # whose name starts with the cache-dir basename (e.g. cache_backup) passes + cache_root = os.path.abspath(CACHE_DIR) + os.sep + if not file_path.startswith(cache_root): raise HTTPException(status_code=404, detail='File not found') if not os.path.isfile(file_path): raise HTTPException(status_code=404, detail='File not found')