Join our Newsletter — 33% off our NHI Course
Home› Guides› Electron and Desktop App Security Guide: Hardening Cross-Platform…
Guide Application Security

Electron and Desktop App Security Guide: Hardening Cross-Platform Apps

PDF for newsletter subscribers · free to read online

← All guides
By Lalit Choda, NHI Mgmt Group Updated 24 October 2026 17 min read
On this page

Electron apps put a full Chromium browser and a Node.js runtime with operating system access inside one installed program, so a single cross-site scripting bug, unsafe IPC handler or unsigned update can become code execution on every user's machine. Electron hosts widely deployed applications; MITRE ATT&CK names Signal, Slack and Microsoft Teams as examples, and lists abuse of Electron applications as its own technique (T1218.015). This guide covers the Electron process and trust model, the renderer hardening settings that matter, IPC design, navigation and external links, fuses and ASAR integrity, code signing and auto-update, local secrets storage, how enterprises should govern third-party Electron apps, detection and a phased rollout. It is written for desktop application developers, application security engineers and the endpoint teams who have to approve and manage these apps. A short comparison with Tauri covers teams choosing a framework.

Key takeaways

  • Treat the renderer as hostile. Keep Electron's secure defaults (context isolation, sandboxing and no Node.js integration) and never turn them off for windows that render remote or user-supplied content.
  • IPC is the real attack surface. Expose one narrow function per channel through contextBridge, validate senderFrame on every message and never hand ipcRenderer to page code.
  • Lock the binary at package time. Flip fuses such as runAsNode and nodeCliInspect off and enable ASAR integrity with onlyLoadAppFromAsar before signing, or attackers can repurpose your signed app.
  • Signing keys and update feeds are crown jewels. A stolen signing certificate or update channel turns your distribution into theirs; keep keys in hardware or cloud signing and protect the CI identity that uses them.
  • You inherit Chromium's patch cycle. Electron supports only the latest three stable majors and cannot push updates for you; an app that ships an old Electron ships old browser vulnerabilities.

The Electron trust model

An Electron app has a main process (Node.js, full operating system access, creates windows) and one or more renderer processes (Chromium, displaying HTML and JavaScript). A preload script runs before page code in the renderer and is the only intended bridge between the two. Security depends on keeping page code from reaching Node.js.

SettingSecure valueDefaultWhat breaks if it is wrong
nodeIntegrationfalseFalse since Electron 5.0.0Any XSS in the renderer can call Node.js APIs; setting it to true also disables the sandbox
contextIsolationtrueTrue since Electron 12.0.0Page scripts share a JavaScript context with the preload and Electron APIs; disabling it also disables sandboxing
sandboxtrue (or app.enableSandbox() before ready)True since Electron 20.0.0Renderer loses operating system level process restrictions
webSecuritytrueTrueSame-origin policy is turned off
allowRunningInsecureContentfalseFalseHTTPS pages can load HTTP scripts and CSS
experimentalFeatures, enableBlinkFeaturesUnsetOffUnfinished or disabled Chromium features become reachable
<webview> allowpopupsAbsentOffEmbedded content can open new windows

Two points from Electron's own documentation are often missed. First, Electron disables some Chrome protections, including Safe Browsing and Certificate Transparency, and calls rendering untrusted content "somewhat uncharted territory". Second, Electron approves all web permission requests (camera, microphone, notifications, geolocation) by default unless you set session.setPermissionRequestHandler(). The safest design loads only the app's own packaged content in privileged windows and opens anything else in the user's default browser.

Renderer hardening

  • Load only secure content: use HTTPS, WSS or FTPS for anything external. Prefer bundling UI assets with the app.
  • Avoid file://: Electron's checklist notes that file:// pages can read any file on the user's machine. Serve app files through a custom scheme with protocol.handle that only returns known paths, and disable the grantFileProtocolExtraPrivileges fuse if you do not serve from file://.
  • Set a Content Security Policy: start from script-src 'self', avoid wildcards, set it through webRequest.onHeadersReceived or a <meta> tag for local files, and add object-src 'none'. See the Security Headers Guide.
  • Escape and sanitise rendered data: chat messages, file names, Markdown and notification text are the usual XSS sources in desktop apps. Frameworks such as React help; their escape hatches do not. See the React and Next.js Security Guide and the Cross-Site Scripting (XSS) Prevention Guide.
  • Handle permission requests: install a handler in every session that loads remote content and approve only named permissions for named origins.
  • Restrict <webview>: handle will-attach-webview on web-contents-created, strip any preload, force nodeIntegration off and check params.src against an allowlist.

IPC and preload design

Context isolation only helps if the bridge is narrow. Electron's context isolation tutorial gives the unsafe pattern explicitly: exposing ipcRenderer.send to the page lets any website loaded in that window send arbitrary IPC messages. The safe pattern exposes one purpose-built function per message.

  • One function per channel: expose functions such as loadPreferences() through contextBridge.exposeInMainWorld, each calling ipcRenderer.invoke on one fixed channel with typed arguments.
  • Never expose raw callbacks: the checklist warns against exposing ipcRenderer.on directly because the event object exposes sender; wrap callbacks and pass only the value needed.
  • Validate the sender on every handler: check event.senderFrame.origin against an allowlist in the main process, deny if the frame is null, and do not trust URLs such as about:blank or blob: that do not identify their controller.
  • Validate arguments in the main process: treat every IPC argument as untrusted input. A handler that accepts a file path, shell command or URL from the renderer is a privilege escalation path unless it checks against a fixed allowlist.
  • Least privilege in the main process: do not build a generic "run this" or "read this file" API. Each privileged capability should exist only because a feature needs it, and be reviewed as such.
ThreatElectron controlATT&CK technique
XSS in renderer reaches Node.jsnodeIntegration: false, contextIsolation: true, sandbox, CSPT1059.007 JavaScript, T1203 Exploitation for Client Execution
Renderer abuses a broad IPC handlerPer-channel functions, senderFrame validation, argument allowlistsT1203
Malicious link opens a dangerous protocol handlershell.openExternal only with validated https: URLsT1204.002 Malicious File
Signed app launched as a generic Node.js runtime or debuggedFuses: runAsNode, nodeOptions, nodeCliInspect offT1218.015 Electron Applications
App JavaScript modified on disk for persistenceASAR integrity plus onlyLoadAppFromAsar, code signingT1554 Compromise Host Software Binary
Malware signed with a stolen certificateHardware-backed or cloud signing, CI identity protection, revocation planT1553.002 Code Signing
Local tokens read by infostealerssafeStorage, cookieEncryption fuse, short-lived tokensT1555 Credentials from Password Stores, T1552.001 Credentials In Files
Malicious plugin or extension loaded by the appSigned, allowlisted extensions; no runtime code downloadT1176 Software Extensions
  • Block unexpected navigation: handle will-navigate and call preventDefault() for anything not on the allowlist. Parse with Node's URL class and compare origins exactly; Electron warns that a startsWith check can be bypassed with a host such as example.com.attacker.com.
  • Deny new windows by default: use setWindowOpenHandler and return { action: 'deny' } unless the URL is expected. Where a link should open, hand it to the system browser.
  • Treat shell.openExternal as a command: Electron's checklist says untrusted input here can lead to arbitrary command execution, because the operating system dispatches the URL to whatever handles its scheme. Allow only https: (and perhaps mailto:) after parsing.

Fuses, ASAR integrity and the packaged binary

Fuses are feature toggles stored in the Electron binary and flipped at package time, before code signing, so that the operating system's signature check stops them being flipped back. Several defaults favour developer convenience over security.

FuseDefaultRecommended for productionWhy
runAsNodeEnabledDisableStops ELECTRON_RUN_AS_NODE turning your signed binary into a general Node.js runtime (use Utility Processes instead of child_process.fork)
nodeOptionsEnabledDisableIgnores NODE_OPTIONS and NODE_EXTRA_CA_CERTS from the environment
nodeCliInspectEnabledDisableIgnores --inspect and --inspect-brk, and stops SIGUSR1 starting the inspector
embeddedAsarIntegrityValidationDisabledEnable (macOS, Windows)Validates app.asar against a hash stored outside the archive
onlyLoadAppFromAsarDisabledEnableWithout it, Electron notes that integrity checking can be bypassed through the code search path
cookieEncryptionDisabledEnable for new appsEncrypts the cookie store with operating system keys; one-way, and requires signing on macOS
grantFileProtocolExtraPrivilegesEnabledDisable if not using file://Removes extra privileges for file:// pages
loadBrowserProcessSpecificV8SnapshotDisabledConsiderSeparate main process snapshot; some startup cost

Flip fuses with @electron/fuses or the Electron Forge fuses plugin, and verify the shipped build in CI with npx @electron/fuses read --app <path>. ASAR integrity is supported on macOS from Electron 16.0.0 and Windows from 30.0.0; the header hash lives in an ElectronAsarIntegrity entry in Info.plist on macOS and an ElectronAsar integrity resource on Windows. Electron Forge 7.4.0 and Electron Packager 18.3.1 or later set this up automatically. Electron still labels the feature experimental and it is not documented for Linux, so Linux builds rely on package manager signatures and file permissions.

Code signing and auto-update

Signing is both a distribution requirement and a security dependency. Electron's documentation lists safeStorage, the cookieEncryption fuse and autoUpdater on macOS as relying on a signed app.

  • macOS: sign and notarise with Apple; Electron Forge uses @electron/osx-sign and @electron/notarize. Keep Apple ID and API credentials for notarisation in the CI secrets store, not in build config.
  • Windows: sign with @electron/windows-sign or your packager's signer. Electron's documentation notes that code signing keys must be held on FIPS 140 Level 2 or Common Criteria EAL 4+ hardware, so they cannot simply be copied to CI; cloud signing services such as Azure Artifact Signing (formerly Azure Trusted Signing) or HSM-backed key services are the usual answer.
  • Protect the signing identity: the signing pipeline is a non-human identity with the power to make malware look like your product. Restrict which pipelines and branches can request a signature, log every signing event and review it. See the Code Signing Security Guide.
  • Update channel: Electron's autoUpdater uses Squirrel.Mac and Squirrel.Windows; alternatives are update.electronjs.org (public GitHub repositories with releases on GitHub Releases), static storage feeds and self-hosted servers. Serve feeds over HTTPS only, verify signatures of downloaded updates, restrict who can publish releases and run update logic only when app.isPackaged is true.
  • Plan revocation: know which versions would stop working if you revoke a certificate and how users will be moved to a re-signed build.

The GitHub code signing certificate theft in December 2022 shows the stakes. A compromised personal access token for a machine account was used to clone repositories for Atom, GitHub Desktop and other deprecated projects, which contained encrypted Windows and Apple Developer ID signing certificates. GitHub revoked the certificates by 2 February 2023, which broke GitHub Desktop for Mac versions 3.0.2 to 3.1.2 and Atom 1.63.0 and 1.63.1 until users updated or downgraded. Signing material in a repository, guarded by one long-lived token, is the failure pattern to avoid.

Local secrets and session data

Desktop apps keep OAuth refresh tokens, session cookies and API keys on disk, which makes them a target for infostealers.

  • Use safeStorage: it encrypts with Keychain on macOS, DPAPI on Windows and kwallet or libsecret on Linux. Electron's documentation is candid about limits: DPAPI protects against other users but not other apps running as the same user, and on Linux without a secret store the basic_text backend uses a hard-coded password and is effectively unprotected. Check getSelectedStorageBackend() and refuse to store long-lived secrets on basic_text.
  • Move to the async API: the synchronous encryptString and decryptString are deprecated and scheduled for removal in Electron 46; encryptStringAsync and decryptStringAsync support key rotation through shouldReEncrypt.
  • Prefer short-lived tokens: local encryption slows theft but does not stop malware running as the user. Short access token lifetimes, refresh token rotation and server-side revocation limit what a stolen token is worth. See the Token and Session Security Guide.
  • Never ship backend secrets in the app: anything in app.asar can be extracted by any user. API keys that must not be public belong behind your own backend. See the Secrets Management Guide.

Keeping Electron current

Electron releases a new major version every eight weeks, tracks even-numbered Chromium releases and supports only the latest three stable majors, with only the latest minor in each line receiving fixes. Because each app bundles its own Chromium and Node.js, Chromium vulnerabilities, including those in CISA's KEV catalogue, stay exploitable in your app until you ship a new Electron. Electron's sandbox documentation states that it cannot push security updates directly, so the app must upgrade itself.

  • Set an Electron patch SLA tied to Chromium security releases, and track the Electron version as a component in your SBOM. See the SBOM Guide.

Choosing a framework: Electron and Tauri

AspectElectronTauri 2
Web engineBundled Chromium per appOperating system WebView
Privileged backendNode.js main processRust core and plugins
BridgePreload with contextBridge and IPCIPC to commands gated by capabilities, permissions and scopes
Patching of web engineApp vendor must ship a new ElectronTauri notes WebView patches can reach users faster through the OS
Extra containmentSandbox, fuses, ASAR integrityIsolation pattern, CSP

Neither framework removes the need for a narrow bridge. Tauri's capability model makes the allowlist explicit in configuration; in Electron the same discipline must come from code review. Choose Electron where consistent rendering and a large JavaScript codebase matter; Tauri suits new projects that can accept platform WebView differences and want an explicit command allowlist.

Managing third-party Electron apps in the enterprise

Most organisations run more Electron apps than they build: chat, meeting, password manager, note-taking and developer tools. Endpoint teams have limited control over the vendor's settings, but several things help.

  • Allowlist by publisher signature, not path, using application control such as Windows App Control for Business or macOS Gatekeeper and MDM policy. Per-user installs into writable profile folders are common with Electron apps and deserve attention. See the Application Allowlisting Guide.
  • Track bundled Electron versions in software inventory and push vendors that lag beyond the supported window.
  • Ask vendors security questions during procurement: fuse state, sandbox and context isolation settings, signing and update process, and how they store tokens.
  • Govern plugins and extensions: editors and chat clients built on Electron load third-party extensions with user rights. The GlassWorm campaign used malicious editor extensions on Open VSX and Microsoft's marketplace to steal npm, GitHub and Open VSX credentials from developers. See the Browser Extension Security Guide.

Detection and measurement

  • Process lineage: alert when an Electron app's process spawns shells, script interpreters or LOLBins, or is launched with --inspect, --remote-debugging-port, --gpu-launcher or with ELECTRON_RUN_AS_NODE set. ATT&CK T1218.015 describes abuse of Electron apps such as teams.exe to run commands as child processes. See the Endpoint Security Guide.
  • File integrity: monitor writes to resources/app.asar and the application folder outside of signed updates (T1554).
  • Signature status: report Electron executables whose signature is missing, invalid or from an unexpected publisher.
  • App telemetry: log denied navigations, denied window opens, rejected IPC senders and permission denials; a spike suggests injected content probing the bridge.

Metrics:

  1. Days between a Chromium security release and your app shipping the corresponding Electron release.
  2. Percentage of releases whose CI fuse check confirms runAsNode, nodeOptions and nodeCliInspect are disabled and ASAR integrity is enabled.
  3. Number of windows with sandbox, contextIsolation or webSecurity weakened (target zero).
  4. Count of IPC handlers without sender validation, from static analysis.
  5. Percentage of managed endpoints running third-party Electron apps on a supported Electron major.

Rolling out the controls

  1. Baseline: scan the codebase for webPreferences settings, ipcMain handlers, shell.openExternal calls and file:// loads, and run npx @electron/fuses read on the current build. Record the Electron version against the support window.
  2. Restore secure defaults: remove any nodeIntegration: true, contextIsolation: false or sandbox: false; move needed Node.js work into the main process behind narrow IPC. Test each window in a pilot build with internal users.
  3. Refactor IPC: replace generic channels with per-feature functions, add senderFrame checks and argument validation, and add unit tests that call handlers from an unexpected origin.
  4. Add navigation and permission handlers and a CSP; ship to a beta channel and watch denial logs before general release.
  5. Flip fuses and enable ASAR integrity in the packaging step, add the CI fuse check, and confirm signing still validates. Roll back by shipping the previous signed build through the update channel; fuses cannot be changed in the field.
  6. Harden signing and updates: move keys to HSM or cloud signing, restrict the signing pipeline, require HTTPS feeds and document a revocation runbook.
  7. Migrate secrets to async safeStorage and enable cookieEncryption for new installs, remembering that it is one-way.

Small teams should use Electron Forge templates (which include the fuses plugin), a cloud signing service and update.electronjs.org or a static feed, and spend review time on IPC. Large organisations should publish an internal Electron baseline (settings, fuses, signing, update and logging requirements), enforce it with CI checks across all desktop products, and use the same baseline as procurement questions for third-party apps.

Common failure patterns

  • Re-enabling Node.js in the renderer to make a feature work quickly, which turns the next XSS bug into remote code execution.
  • A generic IPC bridge such as exposing ipcRenderer.send or an "exec" handler, which context isolation cannot save.
  • Passing chat or document links straight to shell.openExternal without scheme validation.
  • Shipping default fuses, leaving runAsNode and the inspector available so attackers can run their own code under your signature.
  • Signing secrets in the repository or on CI disks, guarded by a single long-lived token, as in the GitHub Desktop and Atom certificate theft.
  • Falling outside Electron's support window, so publicly known Chromium flaws remain exploitable in the shipped app.

Framework mapping

Control areaNIST SP 800-53 Rev. 5NIST CSF 2.0MITRE D3FEND / ATT&CK
Secure renderer defaults and narrow IPCSA-8 Security and Privacy Engineering Principles, CM-7 Least Functionality, SC-18 Mobile CodePR.PS-06T1059.007, T1203
Fuses, ASAR integrity and code signingSI-7 Software, Firmware, and Information IntegrityPR.PS-02T1554, T1553.002, T1218.015
Electron and dependency patchingSI-2 Flaw Remediation, SR-3 Supply Chain Controls and ProcessesID.RA-01, PR.PS-02D3-SU Software Update
Local secret storageSC-28 Protection of Information at RestPR.DS-01T1555, T1552.001
Enterprise allowlisting of desktop appsCM-7PR.PS-05D3-EAL Executable Allowlisting
Endpoint monitoring of Electron processesSI-4 System MonitoringDE.CM-09T1218.015

In ISO/IEC 27001:2022 Annex A the work falls mainly under A.8.25 (secure development life cycle), A.8.28 (secure coding) and A.8.19 (installation of software on operational systems); in CIS Controls v8.1, Control 16 (Application Software Security) for builders and Control 2 (Inventory and Control of Software Assets) for enterprises. See the Application Security Guide.

Practitioner checklist

  • Confirm every window runs with nodeIntegration: false, contextIsolation: true, sandbox: true and webSecurity: true, and call app.enableSandbox() before ready.
  • Expose only per-feature functions through contextBridge and validate senderFrame and arguments in every ipcMain handler.
  • Handle will-navigate, setWindowOpenHandler and permission requests with default-deny allowlists.
  • Validate every URL passed to shell.openExternal and every deep link the app receives.
  • Serve app content through protocol.handle rather than file://, with a CSP starting from script-src 'self'.
  • Disable runAsNode, nodeOptions and nodeCliInspect, enable ASAR integrity with onlyLoadAppFromAsar, and verify fuses in CI before signing.
  • Keep signing keys in HSM or cloud signing, restrict the signing pipeline identity and maintain a revocation runbook.
  • Store tokens with async safeStorage, refuse basic_text on Linux and keep backend secrets out of the app bundle.
  • Stay within Electron's three supported majors with a patch SLA tied to Chromium security releases.
  • For third-party Electron apps, allowlist by publisher, inventory Electron versions and govern extensions.

Standards and references

Related NHI Mgmt Group resources: Application Security Guide · Code Signing Security Guide · Endpoint Security Guide · React and Next.js Security Guide · OWASP Top 10 Guide

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Written and reviewed by Lalit Choda, NHI Mgmt Group. Last updated 24 October 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.