From ad09bed52f83800026e53b2bf3ed2e8fca6bfe17 Mon Sep 17 00:00:00 2001 From: decobot Date: Tue, 5 May 2026 21:40:51 +0800 Subject: [PATCH] fix: validate postMessage origin in LiveControls to prevent XSS Mirrors deco-cx/deco#1183. Adds a trusted-origin allowlist and message shape validation before dispatching `editor::inject`, which calls `eval` on attacker-controlled input. Co-Authored-By: Claude Opus 4.7 (1M context) --- website/components/_Controls.tsx | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/website/components/_Controls.tsx b/website/components/_Controls.tsx index 12c5dc2c5..0bb31a704 100644 --- a/website/components/_Controls.tsx +++ b/website/components/_Controls.tsx @@ -59,8 +59,32 @@ const snippet = (live: Live) => { globalThis.window.location.href = `${href}`; } }; + const TRUSTED_ORIGINS = [ + "https://deco.cx", + "https://admin.deco.cx", + "https://play.deco.cx", + "https://admin-cx.deco.page", + "https://deco.chat", + "https://admin.decocms.com", + "https://decocms.com", + "https://studio.decocms.com", + ]; + const isTrustedOrigin = (origin: string) => + TRUSTED_ORIGINS.indexOf(origin) !== -1 || + (origin.startsWith("https://") && origin.endsWith(".deco.cx")) || + origin === globalThis.window.location.origin; + const onMessage = (event: MessageEvent) => { + if (!isTrustedOrigin(event.origin)) { + return; + } const { data } = event; + if ( + typeof data !== "object" || data === null || + typeof (data as { type?: unknown }).type !== "string" + ) { + return; + } switch (data.type) { case "editor::inject": { return eval(data.args.script);