Electron contextBridge: limiting ipcRenderer.invoke to specific IPC channels
0 reputation · 02 Jan 2021, 05:38 UTC
0 reputation · 02 Jan 2021, 05:38 UTC
Electron's contextBridge is the supported way to expose IPC from a sandboxed preload script to the renderer, but the shape of that exposure is left as a design decision. With contextIsolation enabled (the default since Electron 12) and nodeIntegration disabled, the renderer can only reach what the preload explicitly exposes through contextBridge.exposeInMainWorld.
The unresolved point is how much of ipcRenderer to surface. A single generic wrapper around ipcRenderer.invoke(channel, ...args) keeps the bridge small, but it effectively lets renderer code call any channel the main process handles. Exposing one named function per channel is more restrictive, but it duplicates boilerplate as the API grows.
For windows that load remote content and cannot trust renderer code, the choice has security consequences:
ipcMain.handle listener?sandbox: true change which of these options is feasible?34775 reputation · 02 Jan 2021, 10:53 UTC
For untrusted or remote renderer windows, expose only the IPC channels you intend to allow, using one named function per channel in the preload script.
contextIsolation enabled (default since Electron 12) and nodeIntegration disabled, the renderer cannot reach ipcRenderer directly; it can only call what the preload exposes via contextBridge.exposeInMainWorld.invoke(channel, …args) wrapper effectively trusts every channel handled in the main process. If the whitelist check fails, the renderer can still reach any other exposed channel.window.electron.getUser = () => ipcRenderer.invoke('get-user')) makes the attack surface explicit and eliminates the need for a runtime whitelist.const ALLOWED = ['get-user', 'save-settings'];).const safeInvoke = (channel, ...args) => {
if (!ALLOWED.includes(channel)) throw new Error(`Channel ${channel} not allowed`);
return ipcRenderer.invoke(channel, ...args);
};
contextBridge.exposeInMainWorld('electron', { invoke: safeInvoke });
ipcMain.handle must still validate arguments, authorization, and the target window, because the preload cannot guarantee safe arguments.ipcMain.handle listener for arguments, permissions, and window‑specific policy. This is the trust boundary.sandbox: trueEnabling sandbox adds renderer‑level restrictions (no Node APIs, limited DOM access) but does not remove the need to limit IPC channels. The same options apply: per‑channel exposure or a strictly checked preload whitelist plus main‑side validation.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.