Security posture
Questi contenuti non sono ancora disponibili nella tua lingua.
ha-paneld runs a foreground agent on a wall panel exposing an HTTP API (:8888), a root helper daemon, and an opt-in CDP/DevTools relay. Relaxed mode keeps the turnkey LAN-trust, no-token pairing by default. Optional Hardened mode requires physical access for protected direct LAN requests. Selected routine management actions can proceed through the authenticated Panel Assistant sidebar for an administrator; other protected operations still require approval on the panel’s screen. The remaining unauthenticated API is an accepted residual risk, with network segmentation as the broader control and Home Assistant’s authentication model as the chosen route if general authentication is added. This page records the threat model and the decisions taken.
Trust model
Section titled “Trust model”The panel and Home Assistant normally sit on a trusted LAN, and the app is built around a turnkey, no-token pairing experience. A root or file-level attacker on the panel itself is out of scope (they already own the device). Software already running on the panel is also trusted for the Hardened-mode boundary because loopback requests cannot be attributed securely to the ha-paneld UI rather than another local Android app. Hardened mode is an opt-in physical-presence boundary for networks where not every remote client should be allowed to perform destructive or credential-bearing operations; it is not a complete authentication layer.
Attack surface
Section titled “Attack surface”| Surface | Exposure | Notes |
|---|---|---|
HTTP API :8888 |
unauthenticated; binds dual-stack (::) |
Relaxed mode trusts LAN callers; Hardened mode adds physical approval to selected high-impact routes |
| Runtime profile import/activation | trusted-LAN HTTP workflow; activation is approval-gated in Hardened mode | untrusted YAML is previewed, validated, stored as immutable revisions and explicitly activated; it can select only compiled drivers and cannot grant authority |
CDP / WebView DevTools relay :9222 |
opt-in in Relaxed mode (started via /inspect/start), binds 0.0.0.0, unauthenticated |
full dashboard-session access if started; Hardened mode stops and verifies the process and listener before activation, then prevents restart |
Camera RTSP :8554 |
off by default; while enabled, binds every interface without authentication | H.264 video and optional room audio where microphone access is permitted. Capture requires a visible camera-in-use indicator. Home Assistant camera entity enable asks for approval on the panel in both modes; Configure is a separate owner configuration path. |
Root helper daemon (abstract UNIX socket @hapaneld-helper) |
mutually peer-uid authenticated (SO_PEERCRED: server must be root; client must be the current ha-paneld uid or root), command-allowlisted, character-sanitised, bounded parsing, connection caps |
The app rejects a non-root process that claims the abstract name, and the generic Android shell uid is excluded so an ordinary ADB shell cannot become root through the helper. Its only private-app operation is an explicit Home Assistant mobile app login backup/restore confined to an allowlisted package and fixed descriptor-relative files, with size bounds, staged validation and a recovery journal. |
| Network ADB | opt-in switch; opens 5555 to the LAN when enabled; Android may separately expose paired Wireless debugging on a dynamic TLS port |
documented and off by default; classic TCP ADB and Android Wireless debugging are mutually exclusive with Hardened mode because an ADB client could inject input into the approval screen |
| Accessibility service | locally enabled Android service with window-content and gesture access | Captures keys, dispatches taps, takes screenshots on Android 11 or newer, and handles bounded HOME selection and the app’s own update confirmation. |
| su call-sites | CPU governor regex-sanitised; relay/adb/cdp use constants; Zigbee role allowlisted before shell interpolation | no remaining injection paths |
The state-changing routes on :8888 are where the exposure concentrates:
- In Hardened mode a changed Home Assistant origin cannot inherit the credential stored for the previous endpoint: a replacement credential must arrive in the same save or the old one is cleared. The credential clearing applies in both security modes. Repointing remains a denial-of-service risk because routine configuration is not generally approval-gated.
POST /playdownloads and plays an arbitrary HTTP(S) URL; HTTPS uses the platform trust store and normal hostname verification, while cleartext HTTP remains available for LAN sources. Remote media requests require physical approval in Hardened mode.POST /api/v1/inspect/startstarts the CDP relay (the:9222surface above) in Relaxed mode; Hardened mode closes and disables this surface rather than approving it.- Profile save/activate/rollback routes can change which compiled hardware drivers and capability candidates the panel uses after a controlled service restart. Preview tokens bind save to the exact inspected YAML, activation pins an exact revision/hash, risky declarations are highlighted, and startup falls back to the last-known-good revision. Activation and rollback require physical approval in Hardened mode.
GET /diagreturns device and capability information (useful for reconnaissance). It is intentionally a support tool.GET /api/v1/screenshot.pngandPOST /api/v1/inputview and inject input on the panel. Root/helper routes already expose these; the locally enabled Accessibility service can also supply taps and, on Android 11 or newer, screenshots without root. Hardened mode keeps screenshots available but rejects non-loopback input so a remote caller cannot operate the native approval UI.POST /api/v1/install/componentcan install signer-pinned ha-paneld or minimal Home Assistant mobile app builds. Component installation and an inspected uploaded APK’s commit are protected by Hardened mode.- Full backup export and restore routes can carry configuration secrets and, when explicitly selected on a rooted or helper-backed panel, the allowlisted Home Assistant mobile app login files. Hardened mode approval protects network export and restore; encrypted
.hpbarchives remain the recommended portable format. The helper has no general private-filesystem command and the mobile app login transfer is descriptor-confined, size-bounded and transactionally restored.
The management service uses cleartext HTTP under the trusted-LAN model. Protected requests and sensitive data need a trusted, segmented network; Hardened mode does not encrypt transport.
Browser-mediated attacks
Section titled “Browser-mediated attacks”Browser-mediated attacks are guarded by OriginGuard:
- CSRF: OriginGuard refuses a state-changing request (
POST/PUT/PATCH/DELETE) whoseOrigin/Refereris present and doesn’t match the requestHost, so a malicious LAN web page can’t silently drive these endpoints. Same-origin UIfetches and header-less API clients (curl, Home Assistantrest_command) are unaffected. - DNS rebinding: the
Hostheader must be an IP literal,localhost,*.local(mDNS), or an operator-configured name (http_allowed_hosts); any other hostname is refused (all methods), so an attacker who rebinds their own DNS name to the panel can’t pose as same-origin to read secrets (GET /config/export) or drive the surface. Reaching a panel by IP, which is the norm, is always allowed and is inherently immune to rebinding.
Every request passes the rebinding check first; what happens next depends on whether it changes state, starts privileged work, or is an ordinary read:
- Host check. A request with no
Hostheader passes, because there is no name to rebind. A presentHostmust be an IP literal,localhost,*.localor listed inhttp_allowed_hosts, or the request is refused. - State-changing methods (
POST,PUT,PATCH,DELETE). With noOriginorReferer, the request is allowed as a header-less LAN API client. With one present, it must be parseable and its authority must equal theHost; otherwise it is refused as a cross-origin write. - Active
GETs (those that start capture, a subprocess, sampling or a network refresh). ASec-Fetch-Siteofcross-siteorsame-siteis refused. Otherwise, a presentOriginorReferergoes through the same parse-and-match check as a write. With neither, a request whose user agent looks like a browser but which carries no Fetch Metadata is refused; anything else is allowed as automation. - Ordinary
GETs are allowed, because the browser’s same-origin policy already blocks reading the response cross-origin.
Three behaviours there are easy to misread. A missing Host passes the rebinding check, but a state-changing request with no Host is refused, as is one whose Origin is present but unparseable. Ordinary GETs are deliberately not origin-guarded; it is the side effect of a write, or of an active read, that needs guarding. And active GETs take a third path keyed on Fetch Metadata, failing closed for a browser-shaped request that supplies no positive same-origin evidence while leaving header-less automation working.
Neither guard authenticates the caller. Hardened mode can require physical approval for a protected operation, but decision 3 describes the route for general caller authentication.
APK-installer downloads through AppInstaller are HTTPS-only: the initial URL and every redirect hop must be https, as defence in depth on top of the post-download signer and package pin, which already blocks installing a substituted APK.
Runtime profile files are treated as untrusted data, not plugins. The closed schema can select only drivers compiled into ha-paneld; it carries no shell commands, helper verbs, native code or general scripting. Privileged paths are restricted to core allowlists, and retained WebView artifact metadata selects only core-owned IDs whose HTTPS URL, version and signer hash are compiled into the app. That metadata does not offer a WebView installation or repair. Security-sensitive driver parameters are validated by the owning driver, and declarations never substitute for live root/helper or hardware probes.
Decisions
Section titled “Decisions”- No bespoke API token. A per-panel secret is throwaway and breaks the easy setup. (Rejected.)
- No in-app network allowlist. Restricting who can reach
:8888is delegated to the network layer (router, VLAN or firewall segmentation) rather than reinvented in the app, consistent with leaning on existing platform and infrastructure capabilities. Home Assistant’s own IP allowlist andip_bansecure Home Assistant’s HTTP server, not the panel’s separate:8888, so they do not apply here; network segmentation is the existing control. The in-app path, when warranted, is the Home Assistant authentication model (decision 3). - No general caller authentication. The panel app does not authenticate callers on the local network; the trust model above and Hardened mode are the controls.
- Credential-at-rest encryption is out of scope. A root or file-level attacker on the panel already owns the device.
/playkeeps standard HTTPS verification while allowing cleartext HTTP for LAN audio sources under the LAN-trust model.- Hardened mode is opt-in and device-local. Relaxed mode remains the default so Home Assistant workflows and tooling that manages several panels do not acquire unattended prompts. Hardened approval is process-local, bound to the HTTP peer and the exact protected request, valid for ten minutes and consumed by one matching retry. It cannot be enabled by a network request, backup, restore or an operation across several panels, and it cannot coexist with classic TCP ADB, persistent or explicitly addressed ADB listeners, Android Wireless debugging, or the LAN WebView developer-tools relay. Entry fails closed unless those remote-control paths are verified inactive. Non-loopback tap injection is unavailable while it is active. Loopback software already running on the panel remains trusted. Hardened mode covers credential-bearing export and restore, software and package mutation including a download bound to one exact URL, profile activation, reboot, display and renderer maintenance, database recovery maintenance, and remote media. Enabling the camera through its Home Assistant entity requires panel approval in both modes; Configure is a separate owner setting.
Noi Home Assistant e tutto ciò che fa la Open Home Foundation.
Ultimo aggiornamento:
Commenti
I commenti sono conservati nella discussione di questa pagina su GitHub, quindi caricarli collega il tuo browser a GitHub. Questo browser ricorda la scelta e carica i commenti delle altre pagine quando scorri fino alla loro sezione.
Commenta senza un account GitHub