diff --git a/lib/browser/guest-window-manager.js b/lib/browser/guest-window-manager.js index eb2fd9e8cc60a..2982e8c5115cc 100644 --- a/lib/browser/guest-window-manager.js +++ b/lib/browser/guest-window-manager.js @@ -188,6 +188,14 @@ const canAccessWindow = function (sender, target) { // Routed window.open messages with raw options ipcMainInternal.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, url, frameName, features) => { + // This should only be allowed for senders that have nativeWindowOpen: false + { + const webPreferences = event.sender.getLastWebPreferences(); + if (webPreferences.nativeWindowOpen || webPreferences.sandbox) { + event.returnValue = null; + throw new Error('GUEST_WINDOW_MANAGER_WINDOW_OPEN denied: expected native window.open'); + } + } if (url == null || url === '') url = 'about:blank'; if (frameName == null) frameName = ''; if (features == null) features = ''; diff --git a/spec-main/chromium-spec.ts b/spec-main/chromium-spec.ts index a3d0edd5f6c82..f0a0d73bd274e 100644 --- a/spec-main/chromium-spec.ts +++ b/spec-main/chromium-spec.ts @@ -72,6 +72,36 @@ describe('reporting api', () => { server.close() } }) + + describe('window.open', () => { + it('denies custom open when nativeWindowOpen: true', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + contextIsolation: false, + nodeIntegration: true, + nativeWindowOpen: true + } + }); + w.loadURL('about:blank'); + + const previousListeners = process.listeners('uncaughtException'); + process.removeAllListeners('uncaughtException'); + try { + const uncaughtException = new Promise(resolve => { + process.once('uncaughtException', resolve); + }); + expect(await w.webContents.executeJavaScript(`(${function () { + const ipc = process.electronBinding('ipc').ipc; + return ipc.sendSync(true, 'ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', ['', '', ''])[0]; + }})()`)).to.be.null('null'); + const exception = await uncaughtException; + expect(exception.message).to.match(/denied: expected native window\.open/); + } finally { + previousListeners.forEach(l => process.on('uncaughtException', l)); + } + }); + }); }) describe('window.postMessage', () => {