diff --git a/src/main.ts b/src/main.ts index 60deb42..9d2ecc5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6919,9 +6919,24 @@ ipcMain.handle('open-folder', (_, folderPath: string) => { } }); +// Extensions that shell.openPath would happily execute via the system +// default. Calc.exe via XSS smuggling is the canonical example; this +// list blocks the obvious vectors. Media/text/image extensions are +// still fine — shell.openPath opens them in the OS's default viewer. +const OPEN_FILE_BLOCKED_EXTENSIONS = new Set([ + '.exe', '.bat', '.cmd', '.com', '.ps1', '.vbs', '.vbe', + '.js', '.jse', '.wsf', '.wsh', '.scr', '.msi', '.msp', + '.lnk', '.cpl', '.reg', '.hta', '.jar', '.application' +]); + ipcMain.handle('open-file', async (_, filePath: string): Promise => { if (typeof filePath !== 'string' || !filePath) return false; if (!fs.existsSync(filePath)) return false; + const ext = path.extname(filePath).toLowerCase(); + if (OPEN_FILE_BLOCKED_EXTENSIONS.has(ext)) { + appendDebugLog('open-file-rejected-extension', { ext, path: filePath.slice(0, 200) }); + return false; + } const result = await shell.openPath(filePath); // shell.openPath returns '' on success, an error string on failure. return result === '';