Skip to content

Centrally disable malicious or vulnerable integrations and Apps #186

Description

@frenck

Problem statement

Home Assistant already pulls a central, foundation-maintained list of problems and shows them to users. The Home Assistant Alerts integration has shipped since 2022.8, is enabled by default through default_config, and fetches the alerts database (the alerts.home-assistant.io repo). It gates each alert on the Home Assistant Core and Supervisor versions, fires when a named integration domain is loaded on the instance, and surfaces the result in the Repairs dashboard. The plumbing for "the foundation knows about a problem and Home Assistant finds out" exists today.

What that plumbing cannot do is act. It raises a Repairs notice and stops. When the problem is a cosmetic deprecation, a notice is the right response. When the problem is a custom integration that has turned hostile, a Repairs badge that sits unread for three weeks is not a response at all. Custom integrations and Apps run with full access to the Home Assistant process and to the secrets it holds, which the 2021 security disclosures (a directory traversal in HACS plus several other custom integrations) demonstrated in practice. The only remediation we could offer users at the time was "rename your custom_components folder."

Our own security policy makes the gap explicit. The security page lists as non-qualifying: "Attacks that require the user to install a malicious other software, like a third-party integration, app (formerly known as add-ons), or plugin." A compromised third-party integration is, today, officially nobody's problem to remediate. The closest thing we have to a kill list lives in HACS: the removed file in hacs/default carries a removal_type of critical (with reasons as direct as "Security issues, known to steal auth tokens") and blacklist, and HACS loads it at startup. But that mechanism only nudges the user to open the HACS panel and uninstall, only covers repositories HACS installed, and is exercised so rarely that its action buttons have shipped broken (hacs/integration#3212). It is the right instinct in the wrong place.

  1. We can warn, but we cannot act. The advisory channel notifies. A notification does not protect a user who is asleep, on holiday, or simply not the kind of person who reads Repairs. The protection has to apply itself, because the people most at risk are exactly the people who will not click.
  2. A single compromised popular integration is a fleet-wide event with no fleet-wide response. Maintainer account takeover is now the dominant supply chain pattern (the GlassWorm campaign pushed malicious versions across npm, PyPI, and OpenVSX by compromising maintainers). One poisoned update to a widely-installed custom integration reaches every instance running it, and we have no lever to pull. Removing it from a store stops new installs and does nothing for the thousands of homes already running it. The advisory feed we do have does not close this either: it fires on whether an integration domain is loaded, gated only on the Core and Supervisor versions, so it cannot tell a poisoned version apart from a clean one, and custom integration authors have no channel to publish to it in the first place.
  3. The slowest-moving users are the most exposed and the least equipped. The community keeps asking us to take this seriously. The List of vulnerabilities (CVEs) request (March 2025, still active into 2026) is from a user who updates every four to six weeks and wants security coverage that includes integrations and HACS, not just Core. He cannot audit his dependencies, and he should not have to. The same exposure applies to our own code: when we fix a critical vulnerability in a built-in integration, these instances stay vulnerable for weeks after the fix ships, because nothing contains the affected version between the day we disclose it and the day they finally update.
    Protecting users who cannot assess the security of what they installed is a precondition for inviting less technical people onto the platform at all. We tell people Home Assistant is safe to run in their home. For that to stay true as the audience widens, the foundation needs a way to contain a known attack without depending on each user to read an advisory and act on it in time. This maps to Make Home Assistant More Approachable.

How comparable platforms handle this. Firefox maintains a central add-on blocklist that distinguishes a soft block (disabled by default, the user can override, used for vulnerable but non-malicious add-ons) from a hard block (cannot be re-enabled, used for confirmed malicious ones). The list is pulled to each install and applied locally. Android's Play Protect can remotely disable or remove a confirmed-malicious app already on a device. Browser-extension management in Chrome and Intune works the same way. The package registries (npm, PyPI) are the weak example: they remove the malicious package from the registry but do nothing about the copies already installed, which is the exact failure mode we are positioned to do better than.

Community signals

The mechanism we would build on (momentum)

  • Home Assistant Alerts integration: default-on since 2022.8, pulls a central foundation-maintained database and raises Repairs issues, in practice for built-in integrations and cloud services. The advisory half of this opportunity already ships, but not for the custom integrations where the malicious case lives, and not with per-integration version precision.
  • alerts.home-assistant.io and the alerts repo: the data model ties alerts to integrations, Python packages, Supervisor, and OS. The consumer today matches on a loaded integration domain, gated only on the Core and Supervisor versions. Live examples include pushing users to disable integrations whose clouds are shutting down (Neato, October 2025).
  • HACS removed list: a real critical and blacklist kill list with security reasons, loaded at startup. The closest existing prior art, and a direct source of inspiration for the data shape. Its limits (HACS-only, advisory, broken action buttons) are the argument for moving this capability into Core.

The gap (prior incidents and policy)

The asks

  • List of vulnerabilities (CVEs) (March 2025): wants security communication covering integrations and HACS, from a user who updates infrequently and cannot track dependencies himself. This opportunity answers the protection side of that ask (automatic containment), not the reporting side (a browsable CVE list), which we scope out for a separate opportunity.
  • Risks involved with HACS? (2024): users asking, in plain terms, how exposed they are by running community integrations.
  • Securing our home labs: Home Assistant code review (GitHub Security Lab): external researchers treating the custom-integration trust boundary as a serious attack surface.

Comparable platforms

  • Firefox extension blocklist and the user-facing explanation of soft versus hard blocks.
    The signals cluster around one shape: the foundation can already see and announce a threat, but cannot contain it, and the users who most need containment are the ones who will never act on an announcement.

Scope & Boundaries

In scope

  • A central blocklist of malicious or critically vulnerable integrations and Apps. Maintained by the foundation, keyed by a stable identifier and a version range, carrying a reason and a severity. This extends the existing alerts data model rather than inventing a parallel one. It also needs matching that targets a specific integration version, which the current alerts consumer does not do (it only checks whether a domain is loaded).
  • Two trigger classes. Confirmed malicious or compromised integrations and Apps (supply chain takeover, intentional credential theft), and actively exploitable critical vulnerabilities in otherwise benign ones. Both result in the same action.
  • Built-in (core) integrations, through the critical-vulnerability path. A critical vulnerability in a built-in integration is fixed by shipping a Core release, but that does nothing for the instances that have not updated. The blocklist can disable an affected built-in integration on the vulnerable versions as containment until the user is on a fixed release. The malicious trigger class does not apply here, since we ship this code ourselves; built-in integrations enter scope only through the critical-vulnerability path.
  • Hard disable as the action. A matched integration or App is force-disabled so it cannot load, and Home Assistant restarts to evict it from the running process. There is no user override at the moment a malicious item is matched. The protection is the point.
  • Dependency purge on Home Assistant OS. When the threat lives in a Python dependency, disabling the integration at load time is not enough on Home Assistant OS. The system needs to rebuild to remove the affected dependency from the environment.
  • Clear, honest after-the-fact explanation. When something is disabled, the user is told plainly what was disabled, why, and what they can do, in Repairs and through a notification. Silent disabling is not acceptable even when the action is.
  • Default on for new installations, with a real opt-out. New installs are protected by default. The opt-out exists, is documented, and is honest about what the user is turning off.
  • A promotion path for existing installations. Existing instances are brought onto the protection deliberately, following the one-time-prompt pattern used for other default-changing rollouts.
  • A governance process for entries. Who can add an entry, what evidence is required, how an entry is reviewed and published, and how a wrongly-listed maintainer gets removed. Built on the existing alerts contribution flow.

Not in scope

  • Frontend plugins (Lovelace cards) and themes. We do not have a reliable way to track or version these the way we track integrations and Apps, so they are excluded until that tracking exists.
  • A soft-block or user-overridable mode. We have chosen hard disable for this bet. Whether a deliberately inconvenient override should ever exist is named in Risks, not built here.
  • A browsable CVE registry or vulnerability dashboard for installed integrations. The List of vulnerabilities (CVEs) ask has two halves. This bet delivers the protection half: a slow-moving user is contained from the worst known cases automatically, without having to track anything himself. It does not deliver the visibility half, a per-instance list of CVEs and advisories affecting what the user runs. That visibility piece is real and worth its own opportunity, but folding it in here would turn a focused containment bet into a general security-reporting product. We should open it as a separate opportunity rather than pretend this one answers it.
  • General vulnerability scanning and SBOM generation. This bet contains specific, known threats from a curated list. It does not scan an instance for unknown vulnerabilities or build a software bill of materials.
  • Updating or patching the offending integration to a fixed version. This bet disables; it does not repair. Auto-updating is covered by Apply patch updates automatically on Home Assistant OS.
  • Replacing responsible disclosure or the existing advisory notices. This is the enforcement layer on top of the advisory channel, not a replacement for it.
  • HACS installation and onboarding. Tracked separately in roadmap #94. This bet assumes integrations can arrive through HACS or by hand, and protects against both.

Foreseen solution

Phase 1: The blocklist data and its governance. Extend the alerts data model with an entry type that carries a severity (malicious or critical-vulnerability) and an explicit action (disable), keyed to integration domains and App slugs with version ranges. The harder half of this phase is not the schema, it is the process: who is authorized to publish an entry, what evidence and severity bar is required, how entries are signed and verified so the list itself cannot be used as an attack vector, and how a maintainer disputes a listing. HACS's removed list is the reference for the data shape and a cautionary tale for the process: a kill list nobody maintains or tests is worse than none.

Phase 2: Enforcement in Core and Supervisor. On startup and on a periodic refresh, Home Assistant matches installed integrations and Apps, and the built-in integrations on the running version, against the blocklist. A match force-disables the item so it cannot load, then restarts to remove it from the running process. For a built-in integration this is version-aware containment: the integration is held disabled only while the instance is on an affected version, and is released once the user updates to a fixed Core release. On Home Assistant OS, where the threat is a Python dependency, the system rebuilds to purge it. The user gets a prominent, non-dismissible explanation of what happened and why. This phase carries the real engineering risk: making the disable reliable, making the restart and rebuild safe, and making sure a malformed entry cannot brick an instance.

Phase 3: Default-on and the rollout to existing installs. New installations are protected by default as part of onboarding. Existing installations are brought on deliberately, with a one-time prompt that explains what the protection does and what it will do to a flagged integration, mirroring the rollout pattern used for other default changes.

Phase 1 is the critical path; Phase 2 enforcement cannot be trusted until the governance and signing in Phase 1 are real. Phase 3 depends on Phase 2 being safe. The data-and-governance work and the Core enforcement work can be shaped in parallel once the entry format is agreed.

Risks & open questions

  • Hard disable with no override is the strongest protection and the loudest objection. Power users will read "the foundation can disable software on my machine" as a backdoor regardless of intent. The open question is whether a deliberately inconvenient, well-documented override (a CLI flag or a file the user has to create) should exist for the malicious case, or whether malicious always means non-overridable as it does in a Firefox hard block. The vulnerable-but-benign case is a softer call than the malicious one, and may deserve different treatment.
  • The blocklist becomes a high-value target and a single point of failure. A wrong or compromised entry could disable an integration across the entire fleet in one push. How do we sign entries, who holds the keys, and what is the staged-rollout and rollback story for the list itself? This risk is larger than the feature it guards.
  • Privacy framing has to be airtight. This must remain a pull of a public list, with no report of installed components going upstream, consistent with how the alerts integration already behaves. If it ever reads as "Home Assistant tells the foundation what you run," we have lost the argument. How do we communicate the pull model so it does not look like telemetry or a backdoor?
  • Force-restarting a home is itself a safety event. Disabling and restarting without consent can take down locks, alarms, and heating for the duration. The protection may be correct and still cause harm. How do we time the restart, and do we treat a rebuild on Home Assistant OS (slow, and able to fail) differently from a cheap load-time disable?
  • Who decides what counts as a critical vulnerability, and where is the bar? Malicious is a high-confidence call. Critical vulnerability is a judgment with a severity threshold. Set it too low and we disable working setups over theoretical risk and burn trust; too high and we miss the cases that matter. What scoring and what threshold trigger a disable rather than a plain advisory?
  • False positives hurt maintainers and users at once. A wrongly-listed integration disables real homes and publicly accuses a volunteer maintainer. The appeals path and the speed of de-listing are not optional polish; they are part of whether the community accepts the mechanism at all.
  • The opt-out has to be genuine, and the goal mapping needs confirming. Trust depends on the opt-out being real and honestly described, not buried. Separately, confirm the current strategic goal name against the latest product brief before submission; Approachability is the primary fit, but a trust or safety goal may be more precise this cycle.

Appetite

Large. This is a cross-cutting effort spanning a new foundation-run blocklist service and its governance, Core and Supervisor enforcement, Home Assistant OS rebuild handling, and frontend work for the Repairs explanation and onboarding default. The data-and-governance work (Phase 1) should be sized and shaped as its own track, because it is the gate everything else depends on and its hardest problems are organizational, not technical. Enforcement and rollout (Phases 2 and 3) are roughly two cycles of focused engineering once the entry format and signing model are settled.

Execution issues

To be populated once a bet is approved.

Decision log

Date Decision Outcome
2026-06-11 Created opportunity for roadmap consideration. Initial submission.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels
    No fields configured for Opportunity.

    Projects

    Status
    Awaiting approval

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions