From a60486e2ef648e04366b9895f21dc3dae54efd86 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Thu, 15 Oct 2026 21:32:57 -0500 Subject: [PATCH] validate trusted_proxies at config load Malformed trusted_proxies entries were only parsed per request in get_remote_addr, so a typo logged a warning on every proxied request and the entry was skipped, collapsing all clients behind that proxy into one rate-limit bucket. The config now rejects unparseable entries at startup and get_remote_addr no longer needs the fallback. Host bits are accepted (192.168.1.1/24 reads as 192.168.1.0/24) so a common typo doesn't take down safe mode, which copies the auth section verbatim. --- frigate/api/auth.py | 12 ++++-------- frigate/config/auth.py | 10 ++++++++++ frigate/test/test_config.py | 10 ++++++++++ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/frigate/api/auth.py b/frigate/api/auth.py index d2ac270512..c80ad2cd2c 100644 --- a/frigate/api/auth.py +++ b/frigate/api/auth.py @@ -314,14 +314,10 @@ def get_remote_addr(request: Request): route = list(reversed(forwarded_for.split(","))) logger.debug(f"IP Route: {[r for r in route]}") - trusted_proxies = [] - for proxy in request.app.frigate_config.auth.trusted_proxies: - try: - network = ipaddress.ip_network(proxy) - except ValueError: - logger.warning(f"Unable to parse trusted network: {proxy}") - continue - trusted_proxies.append(network) + trusted_proxies = [ + ipaddress.ip_network(proxy, strict=False) + for proxy in request.app.frigate_config.auth.trusted_proxies + ] # return the first remote address that is not trusted for addr in route: diff --git a/frigate/config/auth.py b/frigate/config/auth.py index 845ec45707..f821f0f2bf 100644 --- a/frigate/config/auth.py +++ b/frigate/config/auth.py @@ -1,3 +1,5 @@ +import ipaddress + from pydantic import Field, field_validator, model_validator from .base import FrigateBaseModel @@ -68,6 +70,14 @@ class AuthConfig(FrigateBaseModel): ), ) + @field_validator("trusted_proxies") + @classmethod + def validate_trusted_proxies(cls, v: list[str]) -> list[str]: + for proxy in v: + ipaddress.ip_network(proxy, strict=False) + + return v + @field_validator("roles") @classmethod def validate_roles(cls, v: dict[str, list[str]]) -> dict[str, list[str]]: diff --git a/frigate/test/test_config.py b/frigate/test/test_config.py index 8818f22457..bc9d08afdd 100644 --- a/frigate/test/test_config.py +++ b/frigate/test/test_config.py @@ -75,6 +75,16 @@ class TestConfig(unittest.TestCase): DetectorTypeEnum.cpu ) + def test_trusted_proxies_reject_invalid_networks(self): + config = { + "auth": {"trusted_proxies": ["172.18.0.0/16", "192.168.1.1/24", "fd00::/8"]} + } + FrigateConfig(**deep_merge(config, self.minimal)) + + config = {"auth": {"trusted_proxies": ["172.18.0.0/33"]}} + with self.assertRaises(ValidationError): + FrigateConfig(**deep_merge(config, self.minimal)) + @patch("frigate.detectors.detector_config.load_labels") def test_model_custom_path(self, mock_labels): mock_labels.return_value = {}