Skip to content

Electron App Attack Surface

An examination of security considerations specific to Electron-based desktop applications, with particular attention to password managers and security tools that use this framework to handle sensitive data.

What Makes Electron Different

Electron combines Chromium's rendering engine with Node.js to allow developers to build desktop applications using web technologies. This architecture delivers rapid development and cross-platform compatibility, but it introduces a fundamentally different threat model compared to native desktop applications.

A native Windows application written in C++ operates within the constraints of the Win32 API. Its access to the filesystem, network, and operating system features is mediated by well-understood system call boundaries. An Electron application, by contrast, runs a full web browser instance with an embedded Node.js runtime. If an attacker achieves JavaScript execution within the renderer process and Node.js integration is available, they gain the full power of Node.js - including filesystem access, child process spawning, network operations, and native module loading.

The core tension in Electron security is this: the renderer process speaks the language of the web (HTML, CSS, JavaScript), inheriting all the injection and content manipulation risks of web applications, while simultaneously having potential access to Node.js APIs that would never be available in a browser tab.

nodeIntegration and contextIsolation

The two most consequential security settings in an Electron application are nodeIntegration and contextIsolation, both configured on the BrowserWindow webPreferences object.

nodeIntegration controls whether the renderer process has direct access to Node.js APIs. When enabled (nodeIntegration: true), any JavaScript executing in the renderer can call require('child_process').exec() or access require('fs'). This means that a cross-site scripting vulnerability - or any other path to JavaScript execution in the renderer - becomes a full remote code execution vulnerability.

Modern Electron versions default nodeIntegration to false, but older applications and applications that were started on earlier Electron versions may still have it enabled. Some developers enable it intentionally because it simplifies the architecture, unaware of (or accepting) the security implications.

contextIsolation determines whether the preload script runs in the same JavaScript context as the web page content. When disabled (contextIsolation: false), the preload script's variables and functions are accessible to the page. An attacker who achieves script execution in the page can manipulate or invoke preload functions, potentially accessing any Node.js-backed APIs the preload exposes.

The secure configuration is nodeIntegration: false and contextIsolation: true. With this combination, the renderer has no direct Node.js access, and the preload script operates in an isolated context where it can selectively expose specific APIs through the contextBridge.

Preload Script Risks

Even with nodeIntegration disabled and contextIsolation enabled, the preload script serves as the bridge between the renderer's web context and the application's Node.js backend. The security of this bridge depends entirely on how carefully the exposed API surface is designed.

Common mistakes in preload scripts include:

  • Exposing overly broad APIs. A preload script that exposes a generic executeCommand(cmd) function to the renderer effectively re-enables nodeIntegration through a thin wrapper.
  • Passing unsanitized arguments. If the preload forwards renderer-supplied strings directly to Node.js file operations or shell commands without validation, injection vulnerabilities arise.
  • Exposing IPC send with arbitrary channels. If the renderer can send messages to any IPC channel, it can invoke main-process handlers that were not intended for renderer-initiated use.

For password managers, the preload script typically handles vault operations, clipboard access, and browser extension communication. Each of these surfaces must be treated as a security boundary with strict input validation.

Protocol Handler Exploitation

Electron applications can register custom protocol handlers (e.g., keeperapp://, mypassmgr://) to handle deep links from web pages or other applications. These handlers parse URIs and take actions based on the path and query parameters.

Security issues arise when:

  • The file:// protocol is not disabled in the renderer, allowing local file reads through crafted page content.
  • Custom protocol handlers do not validate or sanitize URI components before using them in file paths or Node.js operations.
  • Navigation to arbitrary URLs is not restricted, allowing an attacker to redirect the renderer to a malicious page that exploits the application's elevated capabilities.

Electron provides the protocol.registerSchemesAsPrivileged API and the webContents navigation event handlers to control protocol and navigation behavior. Applications that do not implement these controls may be vulnerable to protocol-based attacks, particularly when processing links from untrusted sources (emails, chat messages, web pages).

Auto-Update MITM Risks

Most Electron applications implement auto-update functionality, commonly through the electron-updater package or Electron's built-in autoUpdater module. The update process downloads a new application package from a remote server, verifies it, and applies it - replacing the running application binary.

The security of this mechanism depends on:

  • Transport security. Updates must be fetched over HTTPS with proper certificate validation. Applications that fall back to HTTP, or that disable certificate checks (sometimes done during development and left in production builds), are vulnerable to man-in-the-middle attacks where an attacker substitutes a malicious update package.
  • Signature verification. The downloaded update must be cryptographically signed, and the application must verify the signature against a pinned public key before applying the update. If signature verification is absent or bypassable, a network-level attacker can push arbitrary code to the application.
  • Update server compromise. If the update server is compromised, signed malicious updates can be distributed to all users. This is a supply-chain risk rather than a local one, but it is amplified by the auto-update mechanism's silent, automatic nature.

For password managers specifically, a compromised update mechanism represents an existential threat. An attacker who can push a malicious update to a password manager gains access to the vault decryption key and all stored credentials across the entire user base.

Several historical incidents have demonstrated that Electron auto-update implementations are a realistic attack vector. Developers should use pinned certificates, verify update signatures with a key that is not stored on the update server, and consider implementing update transparency logs.

Implications for Password Managers and Security Tools

Password managers and security tools built on Electron face an elevated risk profile because:

  • They handle master keys and cleartext credentials in the renderer process's memory. Any renderer compromise directly exposes the most sensitive data.
  • They interact with browser extensions over IPC or local network channels, creating additional attack surface.
  • They process untrusted input (URLs, imported vault files, shared folder invitations) that could contain payloads targeting Electron-specific vulnerabilities.
  • Users trust them implicitly - a compromised password manager update would not raise the same suspicion as a compromised game or utility.

Developers of Electron-based security tools should treat every renderer-to-main IPC channel as an external API that hostile input will traverse. The preload bridge should expose the minimum necessary surface. Regular Electron version updates are essential, as Chromium security patches often close vulnerabilities that would affect the renderer.

Defensive Checklist

  • Set nodeIntegration: false and contextIsolation: true on all windows.
  • Audit preload scripts for overly broad API exposure.
  • Restrict navigation with will-navigate and new-window event handlers.
  • Disable file:// protocol access in renderers.
  • Validate and sanitize all custom protocol handler URIs.
  • Enforce HTTPS with certificate pinning for auto-updates.
  • Verify update package signatures against a pinned key.
  • Keep Electron and Chromium dependencies current.
  • Run the Electron security checklist (electron.org/docs/tutorial/security) against each release.