Electron development
High-security and performance-optimized Electron development workflows. Use whenever building, reviewing, extending, or auditing an Electron desktop app — main process, renderer, preload scripts, contextBridge, IPC (ipcMain/ipcRenderer), BrowserWindow config, or packaging with electron-builder/electron-forge. Trigger on any mention of Electron, a desktop app built with Electron, contextIsolation, sandbox mode, preload scripts, IPC bridges, or requests to scaffold/secure/optimize an Electron + TypeScript/React/Vite app. Also trigger when auditing Electron code for security holes (nodeIntegration enabled, disabled contextIsolation, the remote module, missing CSP, unrestricted navigation/window.open) or performance issues (blocking the main process, oversized IPC payloads, listener/memory leaks). Apply the security and performance defaults automatically even if not explicitly requested — they are the non-negotiable baseline, and violating code should be flagged and corrected, not silently written.From its SKILL.md
npx -y skills add Nick-800/skills --skill electron-developmentAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
3 things to look at
- 26 days oldThe repository was created 26 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
7.0 KB, ~1.4k tokens by cl100k_base, as published. Nobody here has run it
Electron Development
Zero-trust architecture for Electron: the renderer is treated as untrusted (it runs web content and can be compromised by a malicious dependency, XSS, or a supply-chain attack), so every capability it has must be deliberately, narrowly, and validatably granted by the main process. Nothing is available "by default."
Workflow
- Determine scope: new app scaffold, a specific feature (e.g. "add a settings IPC channel"), or a security/performance audit of existing code.
- Apply the non-negotiable defaults below to every window and every IPC channel touched, regardless of what was explicitly asked for.
- For audits: walk the red-flag checklist below against the existing code before writing anything new.
- Pull in the relevant reference file (table below) for the deep-dive pattern needed — don't try to hold all of it in working memory, the reference files have the full runnable code.
- Lead with a short explanation of the security/performance rationale before showing code — one or two sentences on why a given mitigation matters, not a lecture.
Non-negotiable security defaults
Every BrowserWindow this skill creates or touches uses:
new BrowserWindow({
webPreferences: {
contextIsolation: true, // renderer JS context is separate from preload/Node context
sandbox: true, // OS-level sandboxing of the renderer process
nodeIntegration: false, // no require(), process, fs, etc. in the renderer
webSecurity: true, // never disable, including "just for dev"
preload: path.join(__dirname, '../preload/index.js'),
},
});
Alongside that:
- No raw IPC or Node modules ever cross
contextBridge.exposeInMainWorld. Expose narrow, named, single-purpose functions only (e.g.getUsers(filters), neveripcRenderer, neverrequire). - Every IPC handler validates both the incoming request and its own response at runtime (Zod or equivalent) — TypeScript types are erased at compile time and enforce nothing once the app is running.
- Navigation and window creation are locked down:
will-navigateandsetWindowOpenHandlerdeny anything not on an explicit allow-list; external links go throughshell.openExternalonly after the URL is validated against that allow-list. - CSP is set as an HTTP response header via
session.defaultSession.webRequest.onHeadersReceived, not a<meta>tag — a header can't be stripped by injected HTML and applies before any script runs. - The
remotemodule is never used (it's removed from modern Electron for good reason — it collapses the process boundary). UseipcMain.handle/ipcRenderer.invokeinstead. - Main process code is never handed a raw file blob to
eval,new Function(), or otherwise dynamically execute based on renderer-supplied content. Seereferences/security-checklist.mdfor the full audit checklist with runnable snippets for each item.
Non-negotiable performance defaults
- Main process stays lightweight: no CPU-heavy synchronous work, no blocking the event loop, no large
in-memory caches. Offload heavy work to a
worker_threadsworker or a separate utility process. - Windows are created lazily, not all at app launch;
show: false+ready-to-showto avoid a white flash. - IPC payloads stay small and flat. Pass file paths or IDs across IPC, not raw binary/file contents;
stream large data instead of round-tripping it through
ipcRenderer.invoke. - Single source of truth for state — don't let main and renderer each maintain their own copy of the same state that can drift.
- Every
useEffect/event listener registered againstipcRenderer.onin React is cleaned up on unmount via the returned unsubscribe (seereferences/ipc-patterns.mdfor the pattern) — otherwise every hot-reload or remount stacks another listener. Seereferences/performance-checklist.mdfor main-process hygiene patterns and common leak sources.
Reference files — pull in as needed
| File | When to read it |
|---|---|
references/security-checklist.md | Full security audit checklist: CSP header setup, navigation lockdown, sandbox verification, red-flag anti-patterns with fixes |
references/performance-checklist.md | Main-process hygiene, worker_threads offloading, memory leak patterns, startup optimization |
references/ipc-patterns.md | The shared-contract + Zod pattern for type-safe IPC, invoke/handle vs send/on, streaming large payloads, React listener cleanup |
references/project-scaffold.md | Full electron-vite + TypeScript + React starter: file tree, electron.vite.config.ts, package.json, tsconfig |
references/packaging-and-updates.md | electron-builder config, code signing requirements per OS, electron-updater security notes (signature verification, HTTPS-only feeds) |
Red flags — refuse or warn, don't silently comply
If a request asks for any of the following, say so explicitly, explain the concrete risk, and propose the secure alternative instead of writing the insecure version:
nodeIntegration: trueorcontextIsolation: false- Using the
remotemodule - Exposing
ipcRenderer(or any Node module) wholesale viacontextBridge - Disabling
webSecurity, even "temporarily" or "just for local dev" setWindowOpenHandlerthat allows arbitrary URLs, or no navigation guard at all- Skipping runtime validation on IPC because "the renderer is trusted, it's our own code" — the renderer is never trusted in this model, since it's the thing most exposed to remote content/dependencies
eval,new Function(), orchild_process.execfed by unvalidated renderer input- Auto-update feeds served over plain HTTP, or without signature verification
Tech stack defaults (used unless the user specifies otherwise)
- Bundler:
electron-vite(Vite for main, preload, and renderer with HMR) - Language: TypeScript in all three processes
- Frontend: React (TSX)
- Validation: Zod for IPC contracts
- Packaging:
electron-builder
What ships with it: 5 files
19.6 KB alongside SKILL.md
references/
- ipc-patterns.md4.5 KB
- packaging-and-updates.md2.7 KB
- preformance-checklist.md4.0 KB
- project-scaffold.md3.0 KB
- security-checklist.md5.5 KB