From 73806810cf6899bd84326cb5510f4e4e2a5be7f2 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Thu, 9 Jul 2026 11:59:12 +0200 Subject: [PATCH] Store recovery HTTP config with the full trusted proxy network The recovery config saved only the network address of each trusted proxy (``ip.network_address``), dropping the prefix length. A configured network like 10.0.0.0/24 was stored as 10.0.0.0 and read back as 10.0.0.0/32, so recovery mode narrowed the trusted proxies to a single host and rejected requests from the real proxy. Store the full network (``str(ip)``) so the config round-trips losslessly. The restored value is re-validated through HTTP_SCHEMA, which accepts both forms, so this is safe on read back. Co-Authored-By: Claude Fable 5 --- homeassistant/components/http/__init__.py | 5 ++++- tests/components/http/test_init.py | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/http/__init__.py b/homeassistant/components/http/__init__.py index 247da3e1b6d2..a56a6d5699ba 100644 --- a/homeassistant/components/http/__init__.py +++ b/homeassistant/components/http/__init__.py @@ -725,8 +725,11 @@ async def start_http_server_and_save_config( ) if CONF_TRUSTED_PROXIES in conf: + # Store the full network (address and prefix) so the recovery config + # round-trips losslessly; ``network_address`` alone drops the netmask + # and would narrow e.g. 10.0.0.0/24 to a single host. conf[CONF_TRUSTED_PROXIES] = [ - str(cast(IPv4Network | IPv6Network, ip).network_address) + str(cast(IPv4Network | IPv6Network, ip)) for ip in conf[CONF_TRUSTED_PROXIES] ] diff --git a/tests/components/http/test_init.py b/tests/components/http/test_init.py index 5b231c8c3687..63ace3f5eb3c 100644 --- a/tests/components/http/test_init.py +++ b/tests/components/http/test_init.py @@ -490,7 +490,7 @@ async def test_storing_config( config = { http.CONF_SERVER_PORT: unused_tcp_port_factory(), "use_x_forwarded_for": True, - "trusted_proxies": ["192.168.1.100"], + "trusted_proxies": ["192.168.1.100", "10.0.0.0/24"], } assert await async_setup_component(hass, http.DOMAIN, {http.DOMAIN: config}) @@ -501,7 +501,9 @@ async def test_storing_config( await hass.async_block_till_done() restored = await http.async_get_last_config(hass) - restored["trusted_proxies"][0] = ip_network(restored["trusted_proxies"][0]) + restored["trusted_proxies"] = [ + ip_network(proxy) for proxy in restored["trusted_proxies"] + ] assert restored == http.HTTP_SCHEMA(config)