Skip to content

Updated

View MarkdownOpen in ChatGPTOpen in Claude

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.