feat: isolate run button#1952
Conversation
Assisted-by: Claude Opus 4.7
| if (location.protocol === ISOLATED_ACTIONS_PROTOCOL) { | ||
| setupIsolatedActionsGlobal(); | ||
| } else { | ||
| await setupFiddleGlobal(); | ||
| } |
There was a problem hiding this comment.
Let's add an isMainFrame check here, exposing only isolated if we're not the main frame
| if (location.protocol === ISOLATED_ACTIONS_PROTOCOL) { | |
| setupIsolatedActionsGlobal(); | |
| } else { | |
| await setupFiddleGlobal(); | |
| } | |
| if (isMainAppFrame()) { | |
| await setupFiddleGlobal(); | |
| } else { | |
| setupIsolatedActionsGlobal(); | |
| } |
| try { | ||
| return new URL(frame.url).protocol === `${ISOLATED_ACTIONS_SCHEME}:`; | ||
| } catch { | ||
| return false; | ||
| } |
There was a problem hiding this comment.
We might want to gate on more than just the protocol? For example we could check the host and pathname too. That would limit the "run fiddle" permissions a little more tightly.
Not sure if I'm overthinking this, open to push back on this. If you're onboard, other related changes inline with (limit-run-permissions-to-run-button) notation.
| try { | |
| return new URL(frame.url).protocol === `${ISOLATED_ACTIONS_SCHEME}:`; | |
| } catch { | |
| return false; | |
| } | |
| return isIsolatedRunButtonDocumentUrl(frame.url); |
with
const RUN_BUTTON_ENTRY_PATH_PREFIX = `/${RUN_BUTTON_ENTRY_NAME}/`;
export function isIsolatedRunButtonDocumentUrl(rawUrl: string): boolean {
try {
const url = new URL(rawUrl);
return (
url.protocol === `${ISOLATED_ACTIONS_SCHEME}:` &&
url.host === ISOLATED_ACTIONS_RUN_BUTTON_HOST &&
url.pathname === '/'
);
} catch {
return false;
}
}| // Refuse path traversal — anything with `..` could escape the | ||
| // upstream output directory once we resolve it. | ||
| if (pathname.includes('..')) { | ||
| return new Response(null, { status: 400 }); | ||
| } |
There was a problem hiding this comment.
This won't safeguard against encoded dots. Not sure what the risk level is here, but there are safer ways to test for this, eg decodeURIComponent + path.posix.normalize(decoded) + normalized.startsWith(entryDirSuffix)
Isolates the run button to a cross-origin iframe to ensure it's rendered as an out-of-process iframe (OOPIF), and is isolated in a separate process to protect against a compromised renderer. This prevents the renderer from being able to programmatically run fiddles, and only the main process or user interaction can start them.