Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Security defaults

An Electron app runs with the user's permissions: it can read and delete their files. If a foreign script gets into a window — from a note copied from the internet, or from a page opened through a link — it gets the same permissions. Security settings restrict the page so that such a script can do nothing.

Three window settings

All three are on by default in current Electron versions. Written out explicitly they look like this:

// main.js
const win = new BrowserWindow({
  width: 900,
  height: 600,
  webPreferences: {
    preload: path.join(__dirname, 'preload.js'),
    contextIsolation: true,
    nodeIntegration: false,
    sandbox: true,
  },
});

You do not have to write them; the behaviour is the same. Writing them out is a useful reminder for whoever reads the code.

SettingDefaultWhat it does
nodeIntegrationfalseThe page cannot call require or use Node.js
contextIsolationtruePreload and the page run in separate JavaScript worlds
sandboxtrueThe operating system restricts the renderer, like a Chrome tab

Context isolation

With isolation, preload and the page have different window objects. The page cannot replace a function that preload uses and cannot reach ipcRenderer. It sees only what was put there with contextBridge.exposeInMainWorld.

Content-Security-Policy

CSP is a rule about where the page may load scripts, styles and images from. It is set with a meta tag in index.html:

<!-- index.html -->
<meta http-equiv="Content-Security-Policy"
      content="default-src 'self'; img-src 'self' data:">

'self' allows only files from the app folder, and img-src additionally allows data: images. Inline scripts and foreign sites are blocked: even if a script tag gets into a note, it does not run.

A narrow bridge

Pass individual functions with a clear purpose through contextBridge:

// preload.js
const { contextBridge, ipcRenderer } = require('electron');
 
contextBridge.exposeInMainWorld('notes', {
  save: (list) => ipcRenderer.invoke('notes:save', list),
});

The page can only save notes. If preload exposed the whole ipcRenderer, the page could send any message to the main process.

Other rules

  • Output user text with textContent, not innerHTML.
  • Do not open foreign sites in a window that has your preload. Open external links in the browser with shell.openExternal(url) in the main process.
  • Keep Electron updated: new versions fix Chromium vulnerabilities.

Common mistake

When they see require is not defined, beginners set nodeIntegration: true and contextIsolation: false, as old articles suggest. After that any script on the page gets full access to the computer. Keep the defaults, move Node.js work into the main process and give the page a function through preload.

Thanks for reading!

Donate to the site — we work hard for you.