Close the renderer privilege boundary: navigation, IPC, permissions, shell
Template tests / tests (pull_request) Failing after 33s
Template tests / tests (pull_request) Failing after 33s
Phase 1 of the improvement plan (PR 2 of the sequence). A remote page could previously inherit the privileged preload bridge: the main window had no navigation guard or popup handler, IPC handlers accepted any sender, every Electron permission was granted to everyone, and shell:openPath accepted an arbitrary renderer-supplied target. - New app/security.js (plain-Node testable) centralizes the policy: app-page identity, navigation/popup denial, deny-by-default permissions, external-URL validation, IPC sender guard, payload budgets, field validators, and a produced-files registry. - Every window (main, region overlay, capture worker) is sandboxed, denies all navigation away from its own page, denies every popup, and refuses webview attachment. - Every IPC channel now rejects events that are not from the main window's top frame on index.html, rejects non-plain/oversized argument bags, and channels with risky inputs validate ids, enums, names, and sizes (path-traversal and prototype-pollution guards included). - Permissions are deny-by-default; the only grant in the app is display capture (+media) for the dedicated capture-worker page. The display-media handler also verifies the requesting frame. - shell:openPath/showItemInFolder are gone. Replacements are intent-specific: openProduced (only files the main process produced this session), revealLinkedArchive (path read from the store, not the renderer), and openExternal (parsed, scheme-checked http(s)/mailto only). - archive:peek removed: unused, and it let the renderer read arbitrary archives by path. - export:run only accepts output directories that came from a dialog pick or remembered settings; anything else re-prompts. - Renderer: description links never navigate; http(s)/mailto open externally via the validated handler. - 12 new security regression tests: hostile navigation targets, permission matrix, sender spoofing (wrong window/subframe/navigated/disposed frames), oversized payloads, traversal/pollution attempts, produced-file registry, and source-level guards (no blanket grants, no generic shell channels, sandbox on every window). Verified: 215 unit tests pass; startup smoke, unit-workflows, sample artifacts, and build-release E2E pass; click self-test still reaches source: stream with markers 3/3 and burst 8/8 under the deny-by-default policy (arm/debounce remain the known pre-existing failures, untouched here); UI screenshot confirms the sandboxed renderer boots. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
+5
-2
@@ -95,8 +95,11 @@ const api = {
|
||||
cleanupPreviews: invoke('preview:cleanup'),
|
||||
},
|
||||
shell: {
|
||||
openPath: invoke('shell:openPath'),
|
||||
showItemInFolder: invoke('shell:showItemInFolder'),
|
||||
// Intent-specific shell access only: files the main process produced,
|
||||
// the guide's linked archive, and scheme-validated external links.
|
||||
openProduced: invoke('shell:openProduced'),
|
||||
revealLinkedArchive: invoke('shell:revealLinkedArchive'),
|
||||
openExternal: invoke('shell:openExternal'),
|
||||
},
|
||||
app: {
|
||||
info: invoke('app:info'),
|
||||
|
||||
Reference in New Issue
Block a user