security: open-file IPC blocks executable extensions
Companion to 4.6.61. The open-file IPC handler (used by the "Open file" buttons in the queue + archive) was previously a plain shell.openPath call with only an existsSync check: if (typeof filePath !== "string" || !filePath) return false; if (!fs.existsSync(filePath)) return false; const result = await shell.openPath(filePath); shell.openPath happily launches any path the OS knows how to execute. An XSS landing through e.g. a smuggled queue item URL that reached the renderer-side openFile global function could pass `C:\\Windows\\System32\\calc.exe` and the IPC would launch calc. Added a deny-list of obvious shell-execution extensions (.exe, .bat, .cmd, .com, .ps1, .vbs, .vbe, .js, .jse, .wsf, .wsh, .scr, .msi, .msp, .lnk, .cpl, .reg, .hta, .jar, .application). Rejected calls log to debug + return false to the renderer. Media + text + image extensions remain unaffected — those open in their normal default-app viewers, which is the intended use case. show-in-folder + open-folder stay permissive on extension since they only open File Explorer (no execution). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
73eaccb483
commit
32e0b1ab7d
15
src/main.ts
15
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<boolean> => {
|
||||
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 === '';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user