VNX-356: Electron app silently grants permissions or accepts invalid certificates
Reports Electron main-process code that answers a security prompt for the user: permission request/check handlers that always grant, certificate-error handlers that always accept, a certificate verifier that always returns 0, and the ignore-certificate-errors switch.
| Field | Value |
|---|---|
| Rule ID | VNX-356 |
| Severity | Low |
| SARIF level | note |
| Kind | sast |
| Languages | JavaScript / TypeScript |
| CWE | CWE-356 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:L/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:L/DI:H/EX:L/EC:N/P:L |
| Tags | missing-unsafe-warning electron permissions tls cwe-356 |
| Source | internal/sast/rules/vnx-356.rego |
Overview
VNX-356 maps to CWE-356: Product UI does not Warn User of Unsafe Actions. In an Electron app, the main process decides whether the user is ever asked about a dangerous action. This rule reports JavaScript/TypeScript code that makes that decision for the user with an unconditional “yes”:
session.setPermissionRequestHandler(...)whose handler calls its callback withtrueunconditionally (camera, microphone, geolocation, notifications and every other permission are granted with no prompt).setPermissionCheckHandler(...)whose handler returnstrueunconditionally.app.on('certificate-error', ...)/webContents.on('certificate-error', ...)whose handler calls its callback withtrueunconditionally.setCertificateVerifyProc(...)whose handler calls its callback with0(trusted) unconditionally.app.commandLine.appendSwitch('ignore-certificate-errors'), unless it sits in a development-only branch (!app.isPackaged,isDev,NODE_ENV === 'development') within the three lines above.
A handler whose body (followed up to eight lines) contains a condition, ternary, comparison, allowlist lookup or switch is a decision and is not reported, nor is a callback given false, nor are test files, comments and string literals. Web confirmation dialogs are not judged: whether an action deserves a prompt is a design question that no line of code answers.
Why This Matters
Browsers warn before a site gets the camera or before loading a page with a bad certificate. An Electron app that grants or accepts everything removes that warning, so a compromised or injected page in the app’s window gets device access, and a network attacker can intercept TLS without the user ever seeing an error.
What Gets Flagged
// FLAGGED
session.defaultSession.setPermissionRequestHandler((webContents, permission, callback) => {
callback(true);
});
app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
event.preventDefault();
callback(true);
});
app.commandLine.appendSwitch('ignore-certificate-errors');
// NOT FLAGGED: grants only named permissions to the app's own origin
session.defaultSession.setPermissionRequestHandler((webContents, permission, callback) => {
const origin = new URL(webContents.getURL()).origin;
callback(origin === 'https://app.example.com' && ALLOWED.has(permission));
});
Remediation
- Grant only the permissions the app needs, and only to origins it trusts; deny everything else (
callback(false)). - Never accept a certificate error unconditionally. If an internal host must be trusted, pin its certificate fingerprint and check the URL.
- Remove
ignore-certificate-errorsfrom production builds.
References
- CWE-356: Product UI does not Warn User of Unsafe Actions
- Electron Security: Handle session permission requests from remote content
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-356
// nosec vnx-356
Or record an ignore rule: vulnetix ignore add --rule vnx-356 --reason "...". See Suppressing findings.