fix(security): deny window.open + block foreign navigation on all BrowserWindows (#377) - #387
Conversation
There was a problem hiding this comment.
All reported issues were addressed across 2 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
Maintainer review — security logic is correct; both cubic P2s resolved (mailto dropped to http(s)-only; the
|
|
Maintainer review — security logic is correct; both cubic P2s resolved (mailto dropped to http(s)-only; the
|
cfc7cbb to
5302b10
Compare
|
Rebased onto Now One open point on your "no test to catch it": the existing T1 ( |
|
Heads up — after #416 merged (it touches the same notification-window region), this went back to CONFLICTING. Needs one more rebase onto current |
5302b10 to
a1687fb
Compare
|
Already done — pushed the rebase onto current Your caveat is covered: Verified locally before pushing: typecheck clean, unit green, full T1 suite green including this PR's own |
Closes #377.
What
Adds navigation/window-open guards to every
BrowserWindow. Previously none of the three windows deniedwindow.openor blocked in-app navigation, so atarget="_blank"link, awindow.open, or a foreign top-level navigation could spawn a chrome-less Electron window or navigate the app frame away from the bundled renderer.A single
hardenWindow(win, { allowExternalLinks })helper is applied at all three creation sites:allowExternalLinks: true) — deny every popup, but route a genuinehttp(s)/mailtotarget (e.g. thetarget="_blank""Report an issue" link inSetup.tsx, or a link inside a note) throughshell.openExternalso it opens in the user's browser instead of silently dying.allowExternalLinks: false) — pure deny/block; this background render of renderer-supplied HTML must never spawn a browser tab on its own.setWindowOpenHandlerreturnsdeny(sodid-create-windowcan't fire);will-navigatecancels any navigation away from the current committed document (reads the target offevent.url, the non-deprecated Electron 42 accessor).Why it's safe
open-externalIPC (shell.openExternal), so nothing legitimately relies onwindow.open.will-navigatenever fires on a real route change — anything reaching it is a foreign/injected navigation.loadFile(main/notification) and the PDFloadURL(data:)are main-process programmatic loads, which don't emitwill-navigate.Testing
security-window-guards.t1.spec.ts: assertswindow.openis denied (no popupBrowserWindowcreated). Verified fail-before (flipping the handler toallowmakes it fail).will-navigateguard is intentionally not asserted by a test: modern Chromium already blocks the only hermetic navigation vectors (data:/about:blank/ missingfile:), so a fail-before-provable test isn't achievable without a networked http target. It's covered by review + reasoning instead of a test that would pass regardless. (Rationale is in the spec's docblock.)Summary by cubic
Hardened all Electron
BrowserWindows: denywindow.openpopups and block foreign navigations. In interactive windows, only HTTP(S) links open in the default browser. Addresses #377.hardenWindow(win, { allowExternalLinks }); applied tomainWindow/notificationWindow(true) and the PDF render window (false).setWindowOpenHandleralways returnsdeny; when allowed, routes only HTTP(S) targets viashell.openExternal(nomailto:or other schemes).will-navigatecancels navigation away from the current document; allowed HTTP(S) URLs open viashell.openExternal.e2e/specs/security-window-guards.t1.spec.tsasserts popup denial.Written for commit a1687fb. Summary will update on new commits.