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 login token never reaches the app at all. GlassHome’s own server holds it and talks to Home Assistant on the app’s behalf, so neither a widget nor the rest of the page can read a key that is not there. To control something, a widget 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: the Home Assistant access token lives only on the GlassHome server, which authenticates the relayed WebSocket itself; the app and its Web Worker hold no token. Widgets send permission-checked requests to the worker (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.