Electron Desktop Apps

Your Electron app ships its source code. Protect it before someone reads it.

Every Electron install carries your JavaScript to the customer's disk, and asar extraction takes one command. Obfuscate the main, preload, and renderer bundles before packaging so the extracted files no longer explain your licensing, business logic, or API usage.

Reality Check

npx @electron/asar extract app.asar out

That is the entire attack. Everything you wrote is now readable in out/ — unless the JavaScript inside was protected first.

All processesMain, preload, and renderer code are all in the archive.
IPC stays stableChannel names and the preload API surface are preserved by exclusion.
Signing unaffectedProtect before packaging; sign and notarize as usual.
Threat Model

What a customer’s machine can see, an attacker can see

Web apps keep most logic on your servers. A desktop app inverts that: trial checks, license validation, premium feature gates, API credentials handling, and proprietary algorithms all ship to hardware you do not control. The question is not whether someone can open the archive — they can — but what they find when they do.

License and trial bypass

Readable isLicensed() logic is a five-minute patch. Obfuscated control flow with VM protection on the entitlement path turns a trivial edit into real reverse-engineering work.

Cloned products

A readable renderer bundle is a free blueprint of your UI logic and workflows. Protection makes copying your app harder than writing one.

API abuse

Endpoints, request signing, and rate-limit handling in clear text invite scripted abuse of your backend. Hiding the how raises the cost of imitation clients.

Protect before you package
npm run build            # bundle main, preload, renderer
npx jso-protector \
  --preset maximum \
  --input dist \
  --output dist-protected
# point electron-builder "files" at dist-protected
npx electron-builder     # package, sign, notarize as usual
The Order of Operations

Bundle → protect → package → sign

  • Bundle each process first. esbuild, Vite, or Webpack output for main, preload, and renderer — protection reads finished JavaScript.
  • Protect all bundles in one pass so identifiers shared across processes stay consistent.
  • Exclude the IPC contract. Channel names and the API your preload exposes via contextBridge are called by name — list them once in the config.
  • Package from the protected folder. electron-builder or Forge consumes dist-protected; asar, signing, and notarization proceed unchanged.
  • Smoke test the packaged app — launch, license flow, IPC round-trips, auto-update — before publishing the release.
Layered Defense

Obfuscation, bytecode, and runtime checks do different jobs

Obfuscation — the readable-source layer

Renaming, string protection, control-flow transforms, and VM protection make extracted files stop explaining themselves. This is the layer that survives extraction.

Bytecode — the source-text layer

Compiling to V8 bytecode hides the text but public decompilers exist. Used after obfuscation it adds friction; used alone it is a speed bump. The jso-protector-electron adapter covers this combination.

Runtime defense — the behavior layer

Runtime defense adds tamper detection and monitoring so a modified build phones home instead of quietly running. Date locks support time-limited builds for trials.

Frequently Asked

Electron protection questions, answered

Is asar enough?

No. asar is a concatenation format, not encryption — one command extracts every file exactly as shipped. Treat it as packaging and protect the JavaScript inside it.

Which processes should I protect?

Main, preload, and renderer — all three are in the archive. Keep IPC channel names and the contextBridge API surface excluded so the processes can still talk to each other.

Does it affect code signing or notarization?

No. Protection runs before packaging, so signing and notarization see ordinary files. Ship the installer exactly as you do today.

Does auto-update still work?

Yes. Updates replace packaged files and never inspect the JavaScript. Run protection in CI so every published release ships protected code.

Obfuscation vs. V8 bytecode — which one?

Different layers. Bytecode hides source text but decompiles with public tooling; obfuscation survives extraction and decompilation. Strongest is protected JavaScript fed into the bytecode step — see the layered defense section above.

How do I debug crash reports from protected builds?

Keep the protection run’s symbol mapping private and use symbolication to translate stack traces from the field back to readable names.

Start Now

Extract your own asar and look

Run the extraction command against your current release and read what your customers can read. Then paste one of those files into the online obfuscator and compare. The difference is the protection layer.