Sep 22, 2026·7 min read·75 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.
GeoNode versions prior to 5.0.3 contain an unrestricted file upload vulnerability (CWE-434) within the document and dataset ingestion architecture. Authenticated low-privileged users can bypass upload validation via direct REST API interactions, file extension masquerading, metadata mutation via PATCH requests, or malicious archive submissions. This allows attackers to store and serve dangerous file types, alter on-disk file references, or trigger path traversal and resource exhaustion during archive extraction.
CVE-2026-55649 is a stored Cross-Site Scripting (XSS) vulnerability in GeoNode versions prior to 5.0.3. The flaw exists because document abstract metadata fields are ingested via the metadata management pipeline and stored in the backend database without HTML sanitization or input neutralization. An authenticated attacker with privileges to create or edit document metadata can inject arbitrary HTML and JavaScript payloads into these fields. When another user, such as an administrator, views the affected document page or catalog listing, the unencoded payload is rendered into the Document Object Model (DOM) and executes within the victim's browser session.
CVE-2026-55622 (GHSA-qx75-2p3r-pwm5) is an improper access control vulnerability (CWE-284) in Canonical LXD and LXC Incus (tracked as GHSA-c9f5-j9c3-mhrg). In multi-tenant deployments utilizing project-based isolation, the REST API handler for instance creation via POST /1.0/instances verifies that the authenticated user has authorization in the destination project specified by the query parameter, but fails to verify whether the user holds read or view permissions for the source instance when executing a copy operation across projects. Consequently, an authenticated client restricted to a single project can clone instances or snapshots from unauthorized projects into their own project, resulting in complete disclosure of the target instance filesystem and embedded credentials.
An authorization bypass vulnerability in Canonical LXD (tracked as GHSA-7mr3-28h5-m5vx and CVE-2026-55621, and as GHSA-64f3-v33m-w89f in Linux Containers Incus) allows an authenticated user with restricted project access to copy custom storage volumes and volume snapshots from unauthorized projects. The flaw resides in the storagePoolVolumesPost REST API handler, which verifies permissions on the destination project but fails to check whether the caller holds view entitlements on the source project or volume specified in the request body.
A missing authorization and configuration validation vulnerability in Canonical LXD and LXC Incus allows authenticated users within restricted projects to bypass project security boundaries. By smuggling prohibited low-level configuration directives (such as raw.lxc or raw.qemu) inside instance snapshots or backup archives, an attacker can restore these configurations within a restricted project and execute arbitrary commands with root privileges on the underlying host operating system.
A symbolic link traversal vulnerability (CWE-59) in Canonical LXD and Linux Containers Incus allows an authenticated user with image import permissions to read and write arbitrary files on the host filesystem. During image archive unpacking, the daemon fails to reject top-level symbolic links for the instance `templates` directory. Subsequent requests to the instance template API endpoints follow this symbolic link outside the instance storage directory with root privileges, enabling complete host compromise.