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.
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.
- A widget can only control the devices you approve when you install it. A weather widget never gets the keys to unlock your door.
- The widget you run is exactly the one I published. It is checked byte-for-byte before it loads.
Why not iframes?
The common way to sandbox third-party code is an iframe per widget. GlassHome deliberately doesn’t: a dashboard full of iframes is slow, janky, and clunky. Instead, the rules about what a widget is allowed to do are enforced for it: a malicious widget in a fast, native-feeling tile still cannot phone home or touch unapproved devices.
The layers
Each layer stops a different thing. The first two are hard guarantees enforced by your browser or GlassHome; the rest raise the bar on top.
Layer 1 — The network lock (stops data leaving)
Your browser is told, up front, the only places a widget may send anything: your Home Assistant and GlassHome. It physically cannot reach any other server, so even a widget that reads your whole dashboard has nowhere to send it. Protects against: 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 sealed-off part of the app that widget code cannot reach, so a widget never holds the keys. To control something, it asks GlassHome, which first checks the request against what you approved at install. Protects against: any widget controlling a device you did not grant it, or reading your Home Assistant login.
Layer 3 — Isolation and no hidden code (extra hardening)
Each widget renders in its own sealed space: it cannot reach into GlassHome or other widgets, and its styling cannot bleed out. Widgets also cannot run code generated or downloaded on the fly. Protects against: one widget tampering with another or with the dashboard, and hidden behavior smuggled in after publish. Unlike Layers 1 and 2, this is defense-in-depth rather than an absolute guarantee.
The permission prompt
When you install a widget that uses your devices, GlassHome shows exactly what it is asking for, in plain language:
“Climate” wants permission to: Control your thermostat
You approve that list, and only that list. If a later update wants more, GlassHome asks you again before it can run, never silently. If a widget tries something outside what you approved, the attempt is blocked and you get a notification.
What a widget can and cannot do
| A widget can… | A widget cannot… |
|---|---|
| Show the entities you give it | Send your data to any other website |
| Control the devices you approve at install | Control devices you did not approve |
| Render inside its own tile | Read your Home Assistant login |
| Use your theme and styling | Reach 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. It can see the entity values shown there; the protection is that Layer 1 leaves it nowhere to send them.
- Layer 3 is hardening, not a wall. A determined attacker who found a browser-level escape could in theory get around it. That is exactly why the guarantees that matter most, Layers 1 and 2, do not depend on it.
- No human review of every widget yet. Today the safety comes from the layers above plus the permissions you grant at install, not from someone reading each widget’s code before publish. 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? Email [email protected] with steps to reproduce, or reach me on the GlassHome Discord. I review every report and gladly credit researchers who report responsibly.