diff --git a/packages/md-react-preview/app/src/preview-block.tsx b/packages/md-react-preview/app/src/preview-block.tsx
index 872d693..dc31bae 100644
--- a/packages/md-react-preview/app/src/preview-block.tsx
+++ b/packages/md-react-preview/app/src/preview-block.tsx
@@ -113,11 +113,17 @@ export function PreviewBlock({
const initialColorScheme = useRef(colorScheme);
useEffect(() => {
if (colorScheme === initialColorScheme.current) return;
- iframeRef.current?.contentWindow?.postMessage({ type: "mrp-theme", theme: colorScheme }, "*");
+ // Security: specify origin instead of "*" to restrict postMessage recipients
+ iframeRef.current?.contentWindow?.postMessage(
+ { type: "mrp-theme", theme: colorScheme },
+ window.location.origin,
+ );
}, [colorScheme]);
useEffect(() => {
function onMessage(e: MessageEvent) {
+ // Security: validate postMessage origin to prevent cross-origin message spoofing
+ if (e.origin !== window.location.origin) return;
if (e.data?.type === "mrp-resize" && e.data?.blockId === blockId) {
setIframeHeight(e.data.height);
}
@@ -198,6 +204,14 @@ export function PreviewBlock({
>
+ {/*
+ Security note: no sandbox attribute is set on this iframe.
+ Preview blocks are authored by trusted developers (markdown authors),
+ and adding sandbox="allow-scripts" alone would break ES module loading
+ (CORS) and postMessage origin checks. Adding both allow-scripts and
+ allow-same-origin together provides no real security benefit for
+ same-origin iframes.
+ */}