diff --git a/src/main.ts b/src/main.ts index bb7044d..60deb42 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6975,7 +6975,20 @@ ipcMain.handle('install-update', () => { }); ipcMain.handle('open-external', async (_, url: string) => { - await shell.openExternal(url); + // Only allow https / http URLs — never let the renderer push a + // file://, javascript:, or shell:-style URL through to the OS + // shell.openExternal handler. The renderer is contextIsolated + + // nodeIntegration: false, but an XSS through (e.g.) a streamer name + // smuggling a payload into a template would otherwise hand the + // attacker shell.openExternal which on Windows happily resolves + // file:///C:/Windows/System32/calc.exe. + if (typeof url !== 'string') return; + const trimmed = url.trim(); + if (!/^https?:\/\//i.test(trimmed)) { + appendDebugLog('open-external-rejected', { url: trimmed.slice(0, 200) }); + return; + } + await shell.openExternal(trimmed); }); // Tracks active standalone clip downloads so cancel-download / window-all-closed