fix(canvas): securely open external links - #3645
Conversation
Generated-By: PostHog Code Task-Id: 2734dc0c-3cac-44d9-bc73-c86e58685df1
|
😎 Merged successfully - details. |
|
React Doctor found no issues in the changed files. 🎉 Reviewed by React Doctor for commit |
| }, | ||
| // External navigation is brokered by the host. The iframe has no popup | ||
| // permission; the host validates the scheme before opening anything. | ||
| openExternal: (url) => post({ type: "open-external", url }), |
There was a problem hiding this comment.
Medium: External launch does not require user activation
A malicious saved or generated canvas can call ph.openExternal() during module evaluation or an effect, causing arbitrary webpages or localhost URLs to open as soon as a viewer loads the canvas. This also runs in dashboard thumbnails, which render canvas code automatically without any click. Require transient user activation before posting the request, or expose this capability only through the trusted anchor-click broker.
There was a problem hiding this comment.
Fixed in 39d785a. The host can't observe gestures inside the null-origin iframe, but a real link click moves focus into it — the open-external handler now drops requests while the canvas iframe is not document.activeElement, so module-eval/effect auto-opens (including offscreen dashboard thumbnails) are ignored. Combined with the PostHog-only https allowlist enforced in the message schema (c1e8a3c) and a per-second throttle. Covered by unit tests on the message path.
PR overviewThis PR updates the canvas sandbox runtime behavior for opening external links from canvas content. It focuses on the There is still an open issue where canvas code can trigger external link launches automatically when a canvas or dashboard thumbnail renders, without a user click. That leaves a malicious saved or generated canvas able to open arbitrary webpages or localhost URLs in a viewer’s environment. No issues have been fixed yet, so the PR still needs a user-activation or trusted-click gating change before the security posture is acceptable. Open issues (1)
Fixed/addressed: 0 · PR risk: 6/10 |
|
… broker Address review findings on the open-external path: - New isSafePostHogUrl in @posthog/shared: only absolute https posthog.com (or subdomain) URLs may leave the canvas sandbox. Enforced in the Zod message schema (safe for every consumer by construction) and re-checked in the FreeformCanvas handler with the blocked URL logged. - Rate-limit successful opens host-side: canvas code can post open-external without a user gesture, so opens are throttled to one per second. - Rewrite the sandbox click interceptor as an exported, unit-tested resolveExternalAnchorUrl inlined into the bootstrap: reads the href attribute (fixes SVG anchors and relative hrefs resolving against the host base URL), matches _blank case-insensitively, brokers absolute URLs only, listens in capture phase (immune to stopPropagation) and defers the open a tick so a canvas preventDefault() is honored. - Replace source-string test assertions with behavioral tests, and cover the message path (allowlist, rejection, throttle) in FreeformCanvas. Generated-By: PostHog Code Task-Id: b3fd12d3-df9b-416d-a660-0dc12ad82803
Addresses the veria-ai review finding: canvas code could call ph.openExternal during module evaluation or an effect, opening URLs as soon as a viewer loads the canvas (including dashboard thumbnails, which render without any click). The host can't observe gestures inside the null-origin iframe, but a real link click moves focus into it, so the open-external handler now ignores requests while the canvas iframe is not the focused element. Combined with the PostHog-only allowlist and the per-second throttle, load-time auto-opens are dropped. Generated-By: PostHog Code Task-Id: b3fd12d3-df9b-416d-a660-0dc12ad82803
Generated-By: PostHog Code Task-Id: b3fd12d3-df9b-416d-a660-0dc12ad82803
|
Note 🤖 stamphog reviewed This is a security-sensitive sandbox change (granting canvases the ability to trigger external URL opens), and the reviewer bot's substantive "opens without user gesture" concern was only addressed by the author's own reply — no independent reviewer has re-confirmed the fix on the current head, unlike the other two issues which greptile explicitly signed off on.
Gate mechanics and policy version
|
|
/truck merge |
|
/trunk merge |
Problem
Links rendered inside freeform canvases cannot open because the iframe intentionally has no popup permission. Granting popup access would unnecessarily broaden the sandbox capability.
Changes
https://posthog.com(or*.posthog.com) URLs, enforced in the Zod message schema and re-checked in the handler; opens are rate-limited host-side since canvas code can post without a user gesture.target="_blank"canvas links without enabling iframe popups: the sandbox click broker reads the href attribute (works for SVG anchors, skips relative hrefs), matches_blankcase-insensitively, is immune tostopPropagation, and honors a canvaspreventDefault().How did you test this?
Automatic notifications
Created with PostHog Code