Element Call iframe is same-origin, so its sandbox is a no-op #43

Open
opened 2026-09-12 01:51:10 -04:00 by jared · 0 comments
Owner

Severity: medium · Type: security · Confidence: high

Location: src/app/plugins/call/CallEmbed.ts:225-259, contrast src/app/features/room/widgets/widgetUtils.ts:34-41 and src/app/features/room/widgets/RoomWidgetView.tsx:38-49

Problem

the bundled Element Call widget is loaded from window.location.origin
(/public/element-call/index.html) into an iframe carrying
sandbox="… allow-scripts allow-same-origin …". For a same-origin document those two tokens together
cancel the sandbox entirely: the frame can reach parent.document, register service-worker messages,
and read localStorage — including cinny_session_v1 / cinny_access_token. The widget code path
right next door (RoomWidgetView) explicitly refuses to render a same-origin widget for exactly this
reason, so the call embed is the one place the stated policy is inverted. EC is first-party bundled
code, so this is defence-in-depth rather than an active hole — but EC renders remote-controlled call
and member data, and any DOM-injection bug there becomes full session compromise.

How to trigger

join a call; in devtools evaluate document.querySelector('iframe[title="Call Embed"]').contentWindow.localStorage.getItem('cinny_session_v1') — it returns the access token.

Suggested fix

serve the EC bundle from a distinct origin (a subdomain or a blob:/data:-less
separate host) so allow-same-origin means the frame's own origin, or drop allow-same-origin and
give EC the storage it needs over the widget postMessage transport.


Filed from the September 2026 client audit (branch lotus @ 4bea4895).

**Severity:** medium · **Type:** security · **Confidence:** high **Location:** `src/app/plugins/call/CallEmbed.ts:225-259`, contrast `src/app/features/room/widgets/widgetUtils.ts:34-41` and `src/app/features/room/widgets/RoomWidgetView.tsx:38-49` ### Problem the bundled Element Call widget is loaded from `window.location.origin` (`/public/element-call/index.html`) into an iframe carrying `sandbox="… allow-scripts allow-same-origin …"`. For a same-origin document those two tokens together cancel the sandbox entirely: the frame can reach `parent.document`, register service-worker messages, and read `localStorage` — including `cinny_session_v1` / `cinny_access_token`. The widget code path right next door (`RoomWidgetView`) explicitly *refuses* to render a same-origin widget for exactly this reason, so the call embed is the one place the stated policy is inverted. EC is first-party bundled code, so this is defence-in-depth rather than an active hole — but EC renders remote-controlled call and member data, and any DOM-injection bug there becomes full session compromise. ### How to trigger join a call; in devtools evaluate `document.querySelector('iframe[title="Call Embed"]').contentWindow.localStorage.getItem('cinny_session_v1')` — it returns the access token. ### Suggested fix serve the EC bundle from a distinct origin (a subdomain or a `blob:`/`data:`-less separate host) so `allow-same-origin` means the frame's *own* origin, or drop `allow-same-origin` and give EC the storage it needs over the widget postMessage transport. --- _Filed from the September 2026 client audit (branch `lotus` @ 4bea4895)._
jared added this to the Audit 2026-09 · Medium & Low milestone 2026-09-12 01:51:10 -04:00
jared added the bugpriority: mediumsecurityarea: calls labels 2026-09-12 01:51:10 -04:00
jared self-assigned this 2026-09-12 01:51:10 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
2026-11-14
Dependencies

No dependencies set.

Reference: LotusGuild/cinny#43