Merge pull request #26914 from Classic298/srcdoc-embed-prompt-confirmation

fix: restore prompt confirmation for sandboxed tool result embeds
This commit is contained in:
Classic298
2026-07-10 13:28:39 -05:00
committed by GitHub
parent b854389951
commit 42f5c3d6f7
2 changed files with 26 additions and 6 deletions
+7 -6
View File
@@ -113,6 +113,7 @@
import FilesOverlay from './MessageInput/FilesOverlay.svelte';
import NotificationToast from '../NotificationToast.svelte';
import Spinner from '../common/Spinner.svelte';
import { isEmbedWindow } from '../common/FullHeightIframe.svelte';
import Tooltip from '../common/Tooltip.svelte';
import Sidebar from '../icons/Sidebar.svelte';
import Image from '../common/Image.svelte';
@@ -795,18 +796,18 @@
const onMessageHandler = async (event: {
origin: string;
source: unknown;
data: { type: string; text: string };
}) => {
const isSameOrigin = event.origin === window.origin;
const type = event.data?.type;
// Prompt-driving message types let an embedding page control the chat
// input / submission. Cross-origin sources are only trusted when the
// user has explicitly opted in via the "iframe Sandbox Allow Same
// Origin" interface setting (the same toggle that governs whether
// rendered iframes receive `allow-same-origin`).
// Prompt-driving types are trusted only same-origin, from our own embed iframes
// (opaque srcdoc origin, submission still confirmed below) or via explicit opt-in.
const promptTypes = ['input:prompt', 'input:prompt:submit', 'action:submit'];
const isTrusted = isSameOrigin || ($settings?.iframeSandboxAllowSameOrigin ?? false);
const isOwnEmbed = isEmbedWindow(event.source);
const isTrusted =
isSameOrigin || isOwnEmbed || ($settings?.iframeSandboxAllowSameOrigin ?? false);
// Non-prompt message types are always restricted to same-origin only.
if (!isSameOrigin && !promptTypes.includes(type)) {
@@ -1,3 +1,10 @@
<script context="module" lang="ts">
// contentWindows of embeds rendered here; Chat.svelte trusts prompt messages from these
const embedWindows = new Set<Window>();
export const isEmbedWindow = (source: unknown): boolean => embedWindows.has(source as Window);
</script>
<script lang="ts">
import { onDestroy, onMount, tick } from 'svelte';
import { config } from '$lib/stores';
@@ -28,6 +35,7 @@
let iframe: HTMLIFrameElement | null = null;
let iframeSrc: string | null = null;
let iframeDoc: string | null = null;
let registeredWindow: Window | null = null;
// Derived: build sandbox attribute from flags
$: sandbox =
@@ -175,6 +183,14 @@ window.Chart = parent.Chart; // Chart previously assigned on parent
const onLoad = async () => {
requestAnimationFrame(resizeSameOrigin);
if (iframe?.contentWindow && iframe.contentWindow !== registeredWindow) {
if (registeredWindow) {
embedWindows.delete(registeredWindow);
}
registeredWindow = iframe.contentWindow;
embedWindows.add(registeredWindow);
}
// if arguments are provided, inject them into the iframe window
if (args && iframe?.contentWindow) {
(iframe.contentWindow as any).args = args;
@@ -188,6 +204,9 @@ window.Chart = parent.Chart; // Chart previously assigned on parent
onDestroy(() => {
window.removeEventListener('message', onMessage);
if (registeredWindow) {
embedWindows.delete(registeredWindow);
}
});
</script>