Skip to content

Harden Electron Navigation, Permission Gates, and Renderer Content Security Policy in Vigil - #2

Open
mozluk wants to merge 2 commits into
Polymarket:mainfrom
mozluk:mozluk-patch-1
Open

Harden Electron Navigation, Permission Gates, and Renderer Content Security Policy in Vigil#2
mozluk wants to merge 2 commits into
Polymarket:mainfrom
mozluk:mozluk-patch-1

Conversation

@mozluk

@mozluk mozluk commented Sep 9, 2026

Copy link
Copy Markdown

Description

This pull request resolves High severity client-side security and privilege escalation findings identified during the workspace audit for the vigil desktop application. Previously, arbitrary protocol schemes could reach OS-level handlers via unconstrained shell.openExternal calls, renderer sessions lacked a sandbox boundary, permissions were open to default handling, and the renderer omitted a Content Security Policy (CSP). This PR enforces an external URL protocol allowlist, sandboxes the renderer process, registers fail-closed permission and navigation guards across all WebContents, and adds a strict meta CSP.

Key Changes & Remediations

1. IPC & External Navigation Hardening (electron/main.ts)

  • Protocol Allowlist: Restricted shell.openExternal strictly to ALLOWED_EXTERNAL_PROTOCOLS (http:, https:). Non-web schemes (such as file:, ms-msdt:, or custom protocols) are blocked and warned rather than handed to the host OS.
  • Origin-Checked Internal Navigation: Added isInternalUrl origin verification for will-navigate and will-redirect to ensure unhandled window navigations cannot load third-party origins into a window with bridge access.
  • Global Navigation Guards: Enforced setWindowOpenHandler on both mainWindow and globally within app.on("web-contents-created") to intercept and deny popup creation while safely delegating external links to the default browser.
  • Webview Denial: Intercepted and cancelled will-attach-webview events to disallow untrusted guest contexts.

2. Sandbox & Permissions (electron/main.ts)

  • Process Sandboxing: Enabled sandbox: true under BrowserWindow.webPreferences to restrict OS-level syscall access from compromised renderers.
  • Deny-by-Default Permissions: Implemented session.setPermissionRequestHandler to automatically reject all browser-level permission inquiries (camera, microphone, geolocation, etc.).

3. Renderer Content Security Policy (electron/renderer/index.html)

  • Strict Meta CSP: Introduced a restrictive CSP meta tag enforcing default-src 'self', object-src 'none', frame-src 'none', and base-uri 'self' to block remote script injections and untrusted framing[cite: 12].

How to Review

  1. Scheme Validation: Check isSafeExternalUrl in electron/main.ts to confirm only http: and https: are permitted.
  2. WebContents Interception: Review app.on("web-contents-created") to verify both webview attachment and window creation handlers fail-closed.
  3. CSP Directives: Inspect <meta http-equiv="Content-Security-Policy"> in electron/renderer/index.html to ensure dangerous sinks (object-src, frame-src) are disabled[cite: 12].

Note

Medium Risk
Security-critical Electron main-process behavior changes (sandbox, navigation, external URLs) could break dev HMR, clipboard onboarding, or link handling if misconfigured; CSP may block unexpected asset or API hosts.

Overview
Hardens the Vigil Electron shell against navigation abuse, privilege escalation, and renderer injection.

Main process (electron/main.ts): shell.openExternal and IPC open-external now only accept http:/https: URLs via isSafeExternalUrl; invalid schemes are logged and ignored. store-session rejects non-string or empty tokens. The renderer runs with sandbox: true. Popups are denied and external links open in the system browser; will-navigate / will-redirect stay in-app only when isInternalUrl matches the dev server origin or file:. A permission handler allows only clipboard read/write for onboarding and denies everything else. Global web-contents-created handlers block <webview> attachment and repeat the popup policy.

Renderer (renderer/index.html): Adds a meta Content-Security-Policy (needed for packaged file:// loads) that limits scripts, styles, fonts, images, and network connections while locking down objects, frames, forms, and base URLs.

Session storage, notifications, and window lifecycle behavior are unchanged aside from clearer error logging when decrypting the stored token.

Reviewed by Cursor Bugbot for commit cf1c7af. Bugbot is set up for automated code reviews on this repo. Configure here.

…curity Policy in Vigil

### Description
This pull request resolves High severity client-side security and privilege escalation findings identified during the workspace audit for the `vigil` desktop application. Previously, arbitrary protocol schemes could reach OS-level handlers via unconstrained `shell.openExternal` calls, renderer sessions lacked a sandbox boundary, permissions were open to default handling, and the renderer omitted a Content Security Policy (CSP). This PR enforces an external URL protocol allowlist, sandboxes the renderer process, registers fail-closed permission and navigation guards across all WebContents, and adds a strict meta CSP.

### Key Changes & Remediations

#### 1. IPC & External Navigation Hardening (`electron/main.ts`)
* **Protocol Allowlist:** Restricted `shell.openExternal` strictly to `ALLOWED_EXTERNAL_PROTOCOLS` (`http:`, `https:`). Non-web schemes (such as `file:`, `ms-msdt:`, or custom protocols) are blocked and warned rather than handed to the host OS.
* **Origin-Checked Internal Navigation:** Added `isInternalUrl` origin verification for `will-navigate` and `will-redirect` to ensure unhandled window navigations cannot load third-party origins into a window with bridge access.
* **Global Navigation Guards:** Enforced `setWindowOpenHandler` on both `mainWindow` and globally within `app.on("web-contents-created")` to intercept and deny popup creation while safely delegating external links to the default browser.
* **Webview Denial:** Intercepted and cancelled `will-attach-webview` events to disallow untrusted guest contexts.

#### 2. Sandbox & Permissions (`electron/main.ts`)
* **Process Sandboxing:** Enabled `sandbox: true` under `BrowserWindow.webPreferences` to restrict OS-level syscall access from compromised renderers.
* **Deny-by-Default Permissions:** Implemented `session.setPermissionRequestHandler` to automatically reject all browser-level permission inquiries (camera, microphone, geolocation, etc.).

#### 3. Renderer Content Security Policy (`electron/renderer/index.html`)
* **Strict Meta CSP:** Introduced a restrictive CSP meta tag enforcing `default-src 'self'`, `object-src 'none'`, `frame-src 'none'`, and `base-uri 'self'` to block remote script injections and untrusted framing[cite: 12].

### How to Review
1. **Scheme Validation:** Check `isSafeExternalUrl` in `electron/main.ts` to confirm only `http:` and `https:` are permitted.
2. **WebContents Interception:** Review `app.on("web-contents-created")` to verify both webview attachment and window creation handlers fail-closed.
3. **CSP Directives:** Inspect `<meta http-equiv="Content-Security-Policy">` in `electron/renderer/index.html` to ensure dangerous sinks (`object-src`, `frame-src`) are disabled[cite: 12].

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 21210cc. Configure here.

Comment thread electron/main.ts
@mozluk

mozluk commented Sep 9, 2026

Copy link
Copy Markdown
Author

Good catch. The permission request handler now maintains a strict allowlist (ALLOWED_PERMISSIONS) specifically granting clipboard-read and clipboard-sanitized-write required for the onboarding copy/paste flows. All other browser-level permissions remain denied by default.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant