CodeVetter · Repo Unpack · Risk map
electron/electron
The largest risks are the security boundary between web content and Node, the breadth of the IPC surface, and the patch-queue maintenance burden. Sandbox/safety defaults are computed from webPreferences in one place (web_contents_preferences.cc) so changes there have wide blast radius; several features (fuses, ELECTRON_RUN_AS_NODE, preload privilege, protocol handlers) deliberately trade security for capability; and ~200 patches to Chromium/Node/V8 must be re-applied and merged on every dependency roll.
- Sandbox defaults are derived, not explicit: RendererProcessPreferences::From marks a renderer sandboxed unless nodeIntegration or nodeIntegrationInWorker is set (or webPreferences.sandbox overrides), and AppendCommandLineSwitches injects --no-sandbox/--no-zygote for unsandboxed renderers — a single pref change flips process isolation.
- ELECTRON_DISABLE_SANDBOX unconditionally appends --no-sandbox at BasicStartupComplete, and ELECTRON_RUN_AS_NODE turns the whole binary into Node — both are env-var-controlled capabilities attackers can sometimes influence.
- Preload scripts run with Node globals even in isolated worlds; the Module.wrapper hack in lib/renderer/init.ts must stay in sync with the bundle's inject list in build/bundle/bundle.mjs, and mistakes leak process/Buffer into the main world (the deletion path only runs for non-context-isolated renderers).
- The IPC surface trusts channel strings end-to-end: internal channels share the same wire as app channels (ipcMainInternal vs ipcMain separated only by the 'internal' bool on the mojo call), so a confused-deputy bug in ipc_dispatch or event.type checks (e.g. rpc-server.ts guards event.type !== 'frame') would let renderer content reach privileged handlers.
- process._linkedBinding exposes the entire native binding table (ELECTRON_*_BINDINGS) to any code running with Node in the renderer when nodeIntegration is on — including process.crash() and process.hang() which deliberately crash/hang the process.
- Fuses change security posture post-build without recompilation: grant_file_protocol_extra_privileges defaults to '1' (on) and run_as_node/node_options/node_cli_inspect default on; embedded_asar_integrity_validation and only_load_app_from_asar default off, so integrity guarantees are opt-in.
- protocol.handle bridges raw request data into Fetch objects: uploadData chunk types (rawData/file/stream/blob) are reassembled by hand and blob bytes come from session.defaultSession regardless of the requesting session (noted in the code as relying on globals) — a subtle cross-session data path.
- <webview> webPreferences are parsed from a DOM attribute string via parse-features-string, and guest-view-manager merges them with embedder-inherited security prefs; malformed or malicious attribute values are a parsing/injection surface, mitigated by the inheritedWebPreferences allowlist.
- security_warnings.cc exists specifically to nag developers about insecure configurations (insecure content, disabled webSecurity, etc.) in devtools — implying the footguns are common enough to need runtime warnings, gated off in tests via ELECTRON_DISABLE_SECURITY_WARNINGS.
- The uncaughtException handler in lib/browser/init.ts swallows main-process crashes into a GUI error box (showErrorBox) instead of exiting — a deliberate 'don't quit' policy that can mask fatal errors in production apps.
- patches/ carries ~200 patches across 13 upstream repos (chromium, node, v8, angle, sqlite, webrtc, boringssl, ffmpeg, ...); each Chromium roll (DEPS chromium_version) requires 3-way merging the queue, and patch rot in security-relevant files is a recurring fragility the repo's own docs warn about.
- spec/index.js kills processes matching the Electron execPath between spec files — on macOS via pgrep -f and on Linux by scanning /proc/*/exe — which would terminate any co-located Electron app sharing the binary path if run outside CI.
- ElectronBrowserMainParts holds most browser-process singletons (node_bindings_, js_env_, node_env_, browser_, fake_browser_process_) with an enforced single self_ instance; ordering bugs in PostEarlyInitialization (env before LoadAppPackage, JoinAppCode before FeatureList re-init) are load-bearing and poorly isolated. (inferred)