Frigate NVR review: from YAML deserialization to 0-click RCE on a local network
GitHub Security Lab's ongoing audit of popular open source projects recently turned to Frigate, a self-hosted network video recorder (NVR) with local object detection and deep Home Assistant integration. The project's container image has been downloaded more than 1.6 million times, making it a worthwhile target for a closer look. What started as a routine triage of CodeQL alerts about unsafe deserialization ended with a chain of three vulnerabilities enabling remote code execution on an unpatched Frigate instance — even one that is not directly reachable from the internet.
The findings described below apply to Frigate 0.12.1. All issues were patched starting with the 0.13.0 Beta 3 release.
Config parsing leads to code execution
Frigate accepts configuration updates through three channels: a local configuration file, its web UI, and the /api/config/save REST API endpoint. No matter the channel, the input eventually reaches a helper function called load_config_with_no_duplicates. That function delegates parsing to yaml.loader.Loader. In PyYAML, the Loader class can instantiate custom constructors defined in the YAML document itself, so a crafted payload is executed directly during parsing rather than merely being read as data.
Submitting a minimal payload that invokes os.popen to run touch /tmp/pwned is enough for a proof of concept. The issue was tracked as CVE-2023-45672.
The missing API protections that make it exploitable
Remote code execution on the host is only half the story. Typical Frigate deployments sit on a user's local network rather than on the public internet, so an attacker would normally need some foothold on that network first. Two further observations about the API change that assumption:
- The API does not implement authentication of its own. Frigate's documentation instead instructs users to place the service behind an authentication proxy or similar protection.
- The API has no CSRF protections at all. Requests that originate from a malicious website will be sent with the visitor's cookies and credentials, and the attacker does not need to read the response for the attack to succeed.
A simple "drive-by" scenario demonstrates the practical impact. A hosted web page runs JavaScript that scans an arbitrary network range — for instance, 10.0.0.1 through 10.0.0.4 — looking for a service that answers on TCP port 5000, the default Frigate port. When a hit is found, the script fires a request against the /api/config/save endpoint with a malicious YAML payload that sets the camera name to pwnd and invokes the deserialization bug. Because the service has no CSRF protection and no built-in authentication, the payload is accepted with no user interaction.
The scanning JavaScript is adapted from the open source localscan utility and can be extended to cover larger ranges, multiple subnets like 192.168.0.0/24, or additional ports. The net result: an attacker with zero knowledge of the victim's network topology or Frigate configuration can achieve 0-click RCE as long as the service is running on a predictable port.
Sneakier options via the config API
The deserialization path is the most direct route to code execution, but the configuration API offers quieter alternatives. It has three capabilities — pulling the current config, saving a new one, and updating an existing one — backed by the /config/raw, /config/save, and related endpoints.
A simple GET to /api/config/raw returns the full configuration. Because there is no authentication layer by default, this leaks MQTT credentials, RTSP passwords, and local file paths that can support further exfiltration. The /config/save endpoint's arguments add another angle: saveonly writes the new configuration without applying it, while restart causes the server to relaunch with the provided configuration immediately.
Chaining these capabilities yields a way to operate Frigate under attacker control while keeping the service owner in the dark:
- Pull the legitimate configuration from
/config/raw. - Submit a modified configuration — disabling recording, redirecting MQTT traffic, or swapping camera feeds to an attacker-controlled source — and invoke
restartto have the server run with it. - Push the original configuration back using
saveonlyso the on-disk and displayed configs look untouched.
Patches and advisories
All three issues were patched in Frigate 0.13.0 Beta 3 and later. The associated advisories are:
- CVE-2023-45670 (GHSA-xq49-hv88-jr6h) — cross-site request forgery in
config_saveandconfig_setrequest handlers - CVE-2023-45671 (GHSA-jjxc-m35j-p56f) — missing authentication
- CVE-2023-45672 (GHSA-qp3h-4q62-p428) — insecure deserialization via
yaml.load
Frigate's out-of-the-box security posture relies on users adding their own protections, such as an authentication reverse proxy. That is workable only if the API is hardened against CSRF as well, because otherwise a visited website can make authenticated requests on the user's behalf. Given how widely Frigate is deployed and how sensitive the data it manages is, users should update to a fixed release promptly and review any additional exposure introduced by their network setup.



