Skip to content

Widget Security

Community widgets are code other people wrote, running on your dashboard. GlassHome is built so that even a malicious widget cannot quietly leak your home’s data or control devices you did not approve. This page explains, plainly, how that protection is layered and where its edges are.

The short version

  • A widget cannot send your home’s data to the internet. Your browser only lets widgets talk to your Home Assistant and to GlassHome, nothing else.
  • A widget can only control the devices you approve when you install it. A weather widget cannot unlock your door, because it never gets the keys to do so.
  • The widget you run is exactly the one I published. It is checked byte-for-byte before it loads.

Why not iframes?

A common way to sandbox third-party code is to put each widget in its own iframe. GlassHome deliberately doesn’t. Iframes are heavy: a dashboard full of them is slow, janky, and clunky to interact with, and that is exactly the experience GlassHome is built to avoid.

Instead the rules about what a widget is allowed to do are enforced for it. That is what actually protects you: a malicious widget in a fast, native-feeling tile still cannot phone home or touch devices you did not approve. The layers below are what make that true.

The layers

Each layer stops a different thing. The first two are the real guarantees: your browser or GlassHome enforces them, and a widget cannot talk its way around them. The rest raise the bar further on top.

Layer 1 — The network lock (stops data leaving)

Your browser is told, up front, the only places a widget is allowed to send anything: your Home Assistant and GlassHome. A widget physically cannot reach any other server. So even a widget that reads everything on your dashboard has nowhere to send it. Protects against: a widget exfiltrating your presence, camera, lock, or sensor data to a stranger’s server.

Layer 2 — The locked-away keys (stops unapproved control)

Your Home Assistant connection and login token live in a separate, sealed-off part of the app that widget code cannot reach. A widget never holds the keys to Home Assistant. When it wants to control something, it asks GlassHome, which checks the request against what you approved at install before doing anything. Protects against: a weather widget unlocking your door, a clock disarming your alarm, or any widget controlling a device you did not grant it, and against any widget reading your Home Assistant login.

Layer 3 — Isolation and no hidden code (extra hardening)

Each widget renders in its own sealed space, so it cannot reach into GlassHome or into other widgets, and its styling cannot bleed out. Widgets also cannot run code that was generated or downloaded on the fly. Protects against: one widget tampering with another or with the dashboard itself, and against a widget smuggling in hidden behavior after it is published. This layer makes misbehavior much harder, but unlike Layers 1 and 2 it is defense-in-depth rather than an absolute guarantee.

The permission prompt

When you install a widget that uses your devices, GlassHome shows you exactly what it is asking for, in plain language:

“Climate” wants permission to: Control your thermostat

You approve that list, and only that list. The widget is held to it from then on. If a later update wants more than you approved, GlassHome asks you again before that update can run, never silently. And if a widget ever tries to do something outside what you approved, the attempt is blocked and you get a notification, so misbehavior is visible, not silent.

What a widget can and cannot do

A widget can…A widget cannot…
Show the entities you give itSend your data to any other website
Control the devices you approve at installControl devices you did not approve
Render inside its own tileRead your Home Assistant login
Use your theme and stylingReach into GlassHome or other widgets’ data
Run hidden, downloaded-on-the-fly code

Not yet covered

I would rather name the edges than pretend they aren’t there.

  • A widget can still read what is already on your dashboard. Layer 1 stops that data from leaving, but a malicious widget on the page can see the entity values shown there. The protection is that it has nowhere to send them, not that it cannot see them.
  • Layer 3 is hardening, not a wall. The isolation between widgets and the no-hidden-code rule raise the bar a lot, but a determined attacker who found a browser-level escape could in theory get around them. That is exactly why the guarantees that matter most, your data not leaving (Layer 1) and your Home Assistant keys staying sealed away (Layer 2), do not depend on Layer 3 at all.
  • No human review of every widget yet. Today the safety comes from the layers above plus the permission you grant at install, not from someone reading each widget’s code before it is published. A review or signing step for the public catalog may come later.

For the technically curious

Layer 1 is a strict Content-Security-Policy egress allowlist. Layer 2 keeps the Home Assistant connection and access token in a Web Worker that widget code cannot reach; widgets send permission-checked requests to it (validated with the same capability definition the consent screen showed you) rather than talking to Home Assistant directly. Layer 3: each widget renders in a closed shadow root, intrinsics are frozen, and eval/Function are disabled by CSP. Separately, every published bundle is SHA-256 verified server-side before it is served.

Reporting a security issue

Found a way around any of this? I want to hear it. Email [email protected] with steps to reproduce, or reach me on the GlassHome Discord. I review every report and am glad to credit researchers who report responsibly.