Sep 22, 2026·7 min read·4 visits
An unauthenticated adjacent attacker can exploit the IPP auto-discovery mechanism in Home Assistant Core to conduct SSRF attacks, potentially accessing local loopback interfaces or internal services.
Home Assistant Core prior to version 2026.2.3 is vulnerable to Server-Side Request Forgery (SSRF) via the IPP integration's auto-discovery mechanism. Unauthenticated mDNS advertisements can trigger HTTP requests that follow malicious redirects to loopback interfaces.
CVE-2026-91129 is a Server-Side Request Forgery (SSRF) vulnerability in Home Assistant Core prior to version 2026.2.3. The flaw is located within the Internet Printing Protocol (IPP) integration component. This component processes local network advertisements to simplify printer configuration.
The vulnerability resides specifically in the auto-discovery mechanism, which processes unauthenticated multicast DNS (mDNS) announcements. By default, the IPP integration parses these Zeroconf packets automatically to establish connections to newly discovered network printers. This automatic handling exposes an attack surface to any device on the local network segment.
A remote, unauthenticated attacker on the same local network can broadcast spoofed _ipp._tcp.local mDNS packets. When Home Assistant receives these packets, it parses the host, port, and path variables and automatically triggers an outbound HTTP metadata query. This query can be redirected by a malicious server to access internal network resources or the local loopback interface.
The root cause of the vulnerability lies in the lack of destination validation during HTTP redirect processing. The IPP integration handles auto-discovery via the async_step_zeroconf entry point within homeassistant/components/ipp/config_flow.py. Upon receiving an mDNS announcement, this function extracts parameters and forwards them to validate_input to fetch printer configuration metadata.
To perform the metadata retrieval, validate_input uses a shared HTTP client session provided by Home Assistant's aiohttp_client module. By default, this HTTP client automatically follows HTTP 3xx redirects. It does not verify whether the redirection target is located on the local loopback address or inside a restricted network interface.
An attacker-controlled printer server can intercept the initial metadata query and return a redirect status code, such as 302 Found or 307 Temporary Redirect. The location header in the response can point to http://127.0.0.1:8123 or other internal-only HTTP APIs. Because the client session follows redirects blindly, it issues a request to the designated target from the trusted context of the Home Assistant daemon.
The vulnerability was addressed by introducing custom SSRF redirection middleware to validate target hosts during the redirection lifecycle. The modification is situated in the generic client session initialization helper in homeassistant/helpers/aiohttp_client.py. This integration path ensures that all components using standard clients benefit from the restriction.
The patch intercepts redirects using a new function named _ssrf_redirect_middleware. This middleware checks if the destination host resolves to a loopback or unspecified address before the client establishes the redirected connection. It raises an SSRFRedirectError if a disallowed destination is discovered.
Below is the implementation of the redirect middleware introduced in the patch. This code block demonstrates how the redirection flow is validated and aborted upon a policy violation. This approach guarantees that redirection handling is centralized.
async def _ssrf_redirect_middleware(
request: aiohttp.ClientRequest,
handler: aiohttp.ClientHandlerType,
) -> aiohttp.ClientResponse:
"""Block redirects from non-loopback origins to loopback targets."""
resp = await handler(request)
connector = request.session.connector
if not (300 <= resp.status < 400) or await _async_is_blocked_host(
request.url.host, connector
):
return resp
location = resp.headers.get(hdrs.LOCATION, "")
if not location:
return resp
redirect_url = URL(location)
if not redirect_url.is_absolute():
return resp
host = redirect_url.host
if await _async_is_blocked_host(host, connector):
resp.close()
raise SSRFRedirectError(
f"Redirect from {request.url.host} to a blocked address"
f" is not allowed: {host}"
)
return respTo prevent attackers from bypassing host checks using trailing dots, the validation routine normalizes hostnames before verification. The utility function _async_is_blocked_host strips trailing dots and matches both direct string representations and resolved IP addresses against loopback criteria. This dual-verification path prevents trivial DNS-based evasion tactics from bypassing the firewall rules.
async def _async_is_blocked_host(
host: str | None, connector: aiohttp.BaseConnector | None
) -> bool:
if not host:
return False
# Normalize hostnames to block FQDN-based bypasses
stripped_host = host.strip().removesuffix(".")
if stripped_host == _LOCALHOST or stripped_host.endswith(_TRAILING_LOCAL_HOST):
return True
with suppress(ValueError):
return _is_ssrf_address(host)
if not isinstance(connector, HomeAssistantTCPConnector):
return False
try:
results = await connector.async_resolve_host(host)
except Exception:
return False
return any(_is_ssrf_address(result["host"]) for result in results)An attack is executed by spoofing mDNS responses on the local network segment. First, the attacker configures an mDNS responder to broadcast a service record for _ipp._tcp.local. This announcement defines the host as the attacker's IP address and specifies an open port under the attacker's control.
When the target Home Assistant instance processes the mDNS broadcast, its Zeroconf listener registers the new IPP service. The IPP integration automatically triggers an outbound HTTP GET request to http://<attacker-ip>:<port>/ipp/printer to fetch the printer's status. The attacker's server receives this request and responds with an HTTP redirect status.
The diagram below outlines the full attack flow and the redirection sequence. The flow begins with the malicious multicast announcement and concludes with the internal request attempt. This visual representation clarifies the direction of the connections.
The redirect instructs Home Assistant to contact a restricted loopback URI, such as http://127.0.0.1:8123/api/ or other internal network services. Since the request originates from localhost, internal APIs that trust the loopback interface without requiring authentication may process the command. This allows the attacker to execute arbitrary state-changing operations or retrieve local configurations.
The technical impact of CVE-2026-91129 is classified as medium, with a CVSS base score of 5.4. Although the attack allows unauthenticated interaction with loopback endpoints, exploitation is restricted to the adjacent network layer. An attacker must reside on the same logical subnet as the Home Assistant server to broadcast the necessary mDNS frames.
The vulnerability compromises both confidentiality and integrity of local services. Successful exploitation allows the attacker to read server response metadata and execute administrative actions if local services trust loopback connections. This bypasses the typical network-layer access controls designed to isolate the smart home controller.
Additionally, the vulnerability can be used to scan other ports or internal endpoints within the local environment. Because the request is sent by the Home Assistant daemon itself, firewalls protecting the host may permit the outbound connection. This turns the Home Assistant device into an internal network pivot point.
The primary remediation for this vulnerability is upgrading Home Assistant Core to version 2026.2.3 or higher. The updated version incorporates the SSRF redirect validation middleware globally across all default HTTP client sessions. No manual configuration changes are required within the IPP integration once the patch is applied.
For environments where immediate upgrading is not feasible, network-level mitigations should be deployed. Administrators can isolate the Home Assistant server on a separate VLAN from untrusted IoT devices or guest users. Blocking cross-VLAN mDNS or IGMP multicast traffic prevents the malicious announcements from reaching the server's network interface.
Furthermore, host-level firewalls can be configured to block outbound traffic from the Home Assistant process to loopback addresses on unexpected ports. Developers implementing custom integrations should ensure they utilize the global client session helper. Creating raw socket connections or independent client instances bypasses the generic middleware protection, reinstating the SSRF attack surface.
CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Core Home Assistant | < 2026.2.3 | 2026.2.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-918 |
| Attack Vector | Adjacent Network (AV:A) |
| CVSS Score | 5.4 |
| EPSS Score | N/A (Pending) |
| Impact | Confidentiality and Integrity Bypass via SSRF |
| Exploit Status | Proof of Concept / Conceptual |
| CISA KEV Status | Not Listed |
The web server receives a URL or similar vector from an upstream source and retrieves the contents without fully validating the destination.
CVE-2026-91130 is a critical DOM-based Cross-Site Scripting (XSS) vulnerability in the Home Assistant open-source home automation platform. Prior to version 2026.7.0, the Statistics Graph card rendered series tooltips using raw HTML string interpolation without escaping user-controlled entity friendly names. By abusing this vulnerability, an authenticated user with low-privilege access can inject arbitrary HTML and JavaScript into entity name fields, which executes in the context of an administrative user's browser session upon hovering over a data point on an affected chart.
A high-severity denial of service vulnerability exists in the emiago/sipgo Go library when parsing stream-based SIP messages. The stream parser fails to validate declared Content-Length header sizes before initiating memory allocations, allowing remote, unauthenticated attackers to trigger process memory exhaustion and application crashes.
CVE-2026-58270 identifies a Regular Expression Denial of Service (ReDoS) vulnerability in Sync-in Server prior to version 2.4.0. An authenticated attacker can supply a complex regular expression in the pathFilters parameter of the sync diff endpoint. When evaluated, this causes catastrophic backtracking, blocking the single-threaded Node.js event loop and rendering the entire server unresponsive.
CVE-2026-56681 is a high-severity authentication bypass vulnerability in 9Router, an AI router and token-saving proxy. The vulnerability arises from an improper trust boundary where the application relies on the client-controlled HTTP header X-9r-Real-Ip to determine whether an incoming request originates from a local (loopback) environment. In deployments where requests can reach the Next.js backend directly—bypassing the sanitizing custom-server.js wrapper—a remote, unauthenticated attacker can spoof their origin by supplying an X-9r-Real-Ip: 127.0.0.1 header.
A rate limiting bypass vulnerability in 9Router versions before 0.5.6 allows unauthenticated remote attackers to circumvent the login progressive lockout mechanism. By manipulating the client-supplied X-9r-Real-Ip HTTP header, an attacker can rotate the tracking IP address, enabling unthrottled brute-force password guessing against the administrative interface.
CVE-2026-58272 is a timing side-channel vulnerability in the authentication endpoint of Sync-in Server before version 2.4.1. Unauthenticated remote attackers can distinguish between valid and invalid usernames due to asymmetric execution paths. When processing invalid usernames, the database query returns early, skipping the computationally expensive bcrypt verification path that is normally triggered for valid accounts.