CVE-2024-32874 (published 2024-05-14T15:37Z)

Frigate is a network video recorder (NVR) with realtime local object detection for IP cameras. Below 0.13.2 Release, when uploading a file or retrieving the filename, a user may intentionally use a large Unicode filename which would lead to a application-level denial of service. This is due to no limitation set on the length of the filename and the costy use of the Unicode normalization with the form NFKD under the hood of `secure_filename()`.


Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/blakeblackshear/frigate
commit_details: repo_url: https://github.com/blakeblackshear/frigate
author: Nicolas Mowen
author_date: 2024-04-27 10:27:23-06:00
msg: Security improvement: ensure user provided file names don't exceed max length (#11129)

* Security fixes

* formatting
repository: repo_url: https://github.com/blakeblackshear/frigate
repo_name: blakeblackshear/frigate
description: NVR with realtime local object detection for IP cameras
repo_language: Python
owner: blakeblackshear
file_changes: filename: media.py
change_type: ModificationType.MODIFY
diff: @@ -392,7 +392,17 @@ def recording_clip(camera_name, start_ts, end_ts):
         if clip.end_time > end_ts:
             playlist_lines.append(f"outpoint {int(end_ts - clip.start_time)}")
 
-    file_name = secure_filename(f"clip_{camera_name}_{start_ts}-{end_ts}.mp4")
+    file_name = f"clip_{camera_name}_{start_ts}-{end_ts}.mp4"
+
+    if len(file_name) > 1000:
+        return make_response(
+            jsonify(
+                {"success": False, "message": "Filename exceeded max length of 1000"}
+            ),
+            403,
+        )
+
+    file_name = secure_filename(file_name)
     path = os.path.join(CACHE_DIR, file_name)
 
     if not os.path.exists(path):
@@ -1167,7 +1177,20 @@ def preview_gif(camera_name: str, start_ts, end_ts, max_cache_age=2592000):
 @MediaBp.route("/<camera_name>/start/<int:start_ts>/end/<int:end_ts>/preview.mp4")
 @MediaBp.route("/<camera_name>/start/<float:start_ts>/end/<float:end_ts>/preview.mp4")
 def preview_mp4(camera_name: str, start_ts, end_ts):
-    file_name = secure_filename(f"clip_{camera_name}_{start_ts}-{end_ts}.mp4")
+    file_name = f"clip_{camera_name}_{start_ts}-{end_ts}.mp4"
+
+    if len(file_name) > 1000:
+        return make_response(
+            jsonify(
+                {
+                    "success": False,
+                    "message": "Filename exceeded max length of 1000 characters.",
+                }
+            ),
+            403,
+        )
+
+    file_name = secure_filename(file_name)
     path = os.path.join(CACHE_DIR, file_name)
 
     if datetime.fromtimestamp(start_ts) < datetime.now().replace(minute=0, second=0):
@@ -1337,6 +1360,14 @@ def review_preview(id: str):
 @MediaBp.route("/preview/<file_name>/thumbnail.webp")
 def preview_thumbnail(file_name: str):
     """Get a thumbnail from the cached preview frames."""
+    if len(file_name) > 1000:
+        return make_response(
+            jsonify(
+                {"success": False, "message": "Filename exceeded max length of 1000"}
+            ),
+            403,
+        )
+
     safe_file_name_current = secure_filename(file_name)
     preview_dir = os.path.join(CACHE_DIR, "preview_frames")
 

programming_language: Python