Systematic security audit of Electron IPC handlers covering path validation, process lifecycle, environment leakage, network security, and authentication gaps
Systematic security audit of Electron IPC handlers covering path validation, process lifecycle, environment leakage, network security, and authentication gaps
source
auto-skill
extracted_at
2026-06-22T14:40:44.079Z
Electron IPC Security Audit
Systematic approach to finding and fixing security vulnerabilities in Electron main process IPC handlers.
Common Vulnerability Patterns
1. Path Validation Gaps
Problem: IPC handlers accept user-controlled paths without validation, enabling directory traversal or access to sensitive locations.
Detection:
Search for ipcMain.handle calls that accept path/directory parameters
Check if validateFsPath or equivalent validation is called before using the path
Look for shell.openExternal with file:// URLs that bypass path validation
8. React Canvas Performance: useState→useRef for High-Frequency Updates
Problem: Canvas pointer position stored as useState triggers full App re-render on every mouse move (60fps), even when no component reads the value during render.
Detection:
Search for useState values that are SET on every mousemove/wheel/pointer event
Check if the value is actually READ during render (vs passed through to children)
Profile: does setting this state cause expensive re-renders?
9. Stabilize useCallback Identity by Reading from Refs
Problem: useCallback hooks that depend on viewport state create new function references on every pan/zoom frame, busting downstream React.memo comparisons.
Detection:
Find useCallback with [viewport] or similar frequently-changing state in dependency array
Check if the function only needs to READ the current value (not close over it)
Look for a corresponding viewportRef that already exists
Fix Pattern:
// Before: new function reference on every viewport changeconst worldToScreen = useCallback((point) => (
worldToScreenPoint(point, viewport)
), [viewport])
// After: stable identity, reads from ref at call timeconst worldToScreen = useCallback((point) => (
worldToScreenPoint(point, viewportRef.current)
), [viewportRef])
Same pattern applies to event listeners:
// Before: listener torn down and recreated on every viewport changeuseEffect(() => {
constonWheel = (e) => setViewport(zoomAtPoint(viewport, ...))
el.addEventListener('wheel', onWheel)
return() => el.removeEventListener('wheel', onWheel)
}, [canvasRef, viewport])
// After: stable listener reads from refuseEffect(() => {
constonWheel = (e) => {
const vp = viewportRef.currentsetViewport(zoomAtPoint(vp, ...))
}
el.addEventListener('wheel', onWheel)
return() => el.removeEventListener('wheel', onWheel)
}, [canvasRef, viewportRef])
10. Per-Entity Token Registries
Problem: A single global bearer token is shared across all clients (terminals, agents, renderer). If one client's token leaks, all operations are compromised.
Detection:
Search for randomUUID() or token generation in server modules
Check if the same token is used for auth validation across all clients
Look for token written to disk files (.mcp.json, mcp-server.json)
Problem: Expensive O(n²) computations (discovery graphs, connection candidates) run on every render frame during tile drags, causing frame drops with many tiles.
Detection:
Search for nested loops over tiles array in useMemo hooks
Check if the useMemo depends on tiles (changes on every drag frame)
Look for findDiscoveryMatch or similar O(n) functions called in a loop
Fix Pattern:
const negotiatedDiscoveryState = useMemo(() => {
// ... build connection graph from worker results ...// Skip O(n²) auto-discovery during active drags — connections// don't need to be recomputed while tiles are movingconst isActiveDrag = dragState.type === 'tile' ||
dragState.type === 'group' ||
dragState.type === 'resize' ||
dragState.type === 'connection'if (autoConnectionsEnabled && !isActiveDrag) {
for (const tile of tiles) {
const discovery = findDiscoveryMatch(tile.id, tiles, ...)
// ... process discovery match
}
}
return { connectedTileIds, byTileConnections, ambientRoutes }
}, [autoConnectionsEnabled, tiles, dragState, ...])
Parallel Audits: Launch subagents for security, correctness, performance, architecture, tests
Vetting: Spot-check findings against actual code, reject false positives
Implementation: Start with S-effort fixes, batch related changes
Verification: Run typecheck and test suite after each batch
Common False Positives
CORS on loopback servers: Often flagged but may be intentional for local dev tools
process.env in test files: Usually acceptable in test contexts
Missing auth on health endpoints: Health checks typically don't need auth
Verification Commands
# Typecheck
npx tsgo -p tsconfig.tsgo.json --noEmit
# Run security-focused tests
node --testtest/stream-ssrf.test.ts test/security-hardening.test.ts test/mcp-auth.test.ts
# Run full test suite
npm test