From 416a9b7692e052be98ad503704d26c7ef7a4c88d Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Thu, 19 Mar 2026 09:42:33 -0500 Subject: [PATCH] Validate preview filename and camera access (#22530) * validate preview filename and camera access * correctly handle camera names with dashes --- frigate/api/media.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/frigate/api/media.py b/frigate/api/media.py index 03aa8ea5b..dad7a3d87 100644 --- a/frigate/api/media.py +++ b/frigate/api/media.py @@ -1893,7 +1893,7 @@ async def review_preview( "/preview/{file_name}/thumbnail.webp", dependencies=[Depends(allow_any_authenticated())], ) -def preview_thumbnail(file_name: str): +async def preview_thumbnail(request: Request, file_name: str): """Get a thumbnail from the cached preview frames.""" if len(file_name) > 1000: return JSONResponse( @@ -1903,6 +1903,17 @@ def preview_thumbnail(file_name: str): status_code=403, ) + # Extract camera name from preview filename (format: preview_{camera}-{timestamp}.ext) + if not file_name.startswith("preview_"): + return JSONResponse( + content={"success": False, "message": "Invalid preview filename"}, + status_code=400, + ) + # Use rsplit to handle camera names containing dashes (e.g. front-door) + name_part = file_name[len("preview_") :].rsplit(".", 1)[0] # strip extension + camera_name = name_part.rsplit("-", 1)[0] # split off timestamp + await require_camera_access(camera_name, request=request) + safe_file_name_current = sanitize_filename(file_name) preview_dir = os.path.join(CACHE_DIR, "preview_frames")