Phase 1 of the improvement plan (ai_prompts/prompt4.md), PR 2 of the sequence. Mirrors GitHub PR Twest2/StepForge#6.
New app/security.js centralizes navigation/popup denial, deny-by-default permissions (display capture only for the capture worker), IPC sender guard, payload budgets, field validators, produced-files registry.
All three windows sandboxed with navigation/popup/webview denial.
Every IPC channel validates sender + arguments; shell access is intent-specific (openProduced/revealLinkedArchive/openExternal); archive:peek removed; export:run output dirs constrained to dialog/settings-sourced paths.
Renderer links never navigate the privileged window.
Verified: 215 unit tests incl. 12 new security regression tests; startup smoke/unit-workflows/sample-artifacts/build-release E2E pass; click selftest unchanged (stream source, 3/3 markers, 8/8 burst; arm/debounce failures are the pre-existing defect scheduled for PR 5).
Phase 1 of the improvement plan (ai_prompts/prompt4.md), PR 2 of the sequence. Mirrors GitHub PR Twest2/StepForge#6.
- New app/security.js centralizes navigation/popup denial, deny-by-default permissions (display capture only for the capture worker), IPC sender guard, payload budgets, field validators, produced-files registry.
- All three windows sandboxed with navigation/popup/webview denial.
- Every IPC channel validates sender + arguments; shell access is intent-specific (openProduced/revealLinkedArchive/openExternal); archive:peek removed; export:run output dirs constrained to dialog/settings-sourced paths.
- Renderer links never navigate the privileged window.
Verified: 215 unit tests incl. 12 new security regression tests; startup smoke/unit-workflows/sample-artifacts/build-release E2E pass; click selftest unchanged (stream source, 3/3 markers, 8/8 burst; arm/debounce failures are the pre-existing defect scheduled for PR 5).
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]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Phase 1 of the improvement plan (ai_prompts/prompt4.md), PR 2 of the sequence. Mirrors GitHub PR Twest2/StepForge#6.
Verified: 215 unit tests incl. 12 new security regression tests; startup smoke/unit-workflows/sample-artifacts/build-release E2E pass; click selftest unchanged (stream source, 3/3 markers, 8/8 burst; arm/debounce failures are the pre-existing defect scheduled for PR 5).
Merged into main as
6ffef69(same-SHA merge to both forges; GitHub mirror PR Twest2/StepForge#6 MERGED, CI green on ubuntu+windows). Closing.Pull request closed