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/../<sibling>/<file>. 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) <noreply@anthropic.com>
This commit is contained in:
Classic298
2026-06-01 10:17:02 -07:00
committed by GitHub
co-authored by Claude Opus 4.7
parent 07cbc91a8e
commit b0fa4384ea
+4 -1
View File
@@ -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')