You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As Rocket.Chat Desktop continues to serve millions of users globally across macOS, Windows, and Linux, modernizing its core architecture is critical to keeping pace with security standards and energy efficiency expectations.
This RFC proposes three critical, interconnected architectural upgrades to Rocket.Chat.Electron:
Secure-by-Default Window Isolation: Moving from legacy configurations with contextIsolation: false and nodeIntegration: true to a modern, zero-trust context-isolated environment via contextBridge across all BrowserWindow targets (rootWindow, logViewerWindow, videoCallWindow).
Cryptographic Update Integrity: Introducing explicit post-download signature and SHA256 checksum validations to safeguard the auto-update mechanism against man-in-the-middle (MitM) and supply-chain tampering.
Event-Driven & Power-Aware Resource Tuning: Replacing wasteful 1-second interval DOM-polling with surgical MutationObserver subscriptions and leveraging Electron's powerMonitor API to put background tabs, rendering cycles, and event loops to sleep when idle.
If a Cross-Site Scripting (XSS) vulnerability is discovered within any local renderer or if untrusted markup is rendered (e.g., via HTML-based logs or shared views), an attacker gains full access to Node.js built-ins (require('child_process'), require('fs')). This enables Remote Code Execution (RCE) directly on the user's host machine.
By enforcing contextIsolation: true and nodeIntegration: false, the renderer process is separated from the preload script, protecting the Node.js runtime from exploit injection.
2.2. Architectural Blueprint: The Secure Bridge
We propose a complete refactoring of the window instantiation preferences and IPC routing.
sequenceDiagram
participant Renderer as Renderer Process (Web Content)
participant Bridge as Context Bridge (Preload Script)
participant Main as Main Process (Node.js)
Renderer->>Bridge: Calls filtered API: RocketChatDesktop.send('log-action', data)
Note over Bridge: Validates channel is allowed<br/>and sanitizes payload
Bridge->>Main: ipcRenderer.send('log-action', sanitizedData)
Note over Main: Executes Node.js logic safely
While electron-updater performs generic certificate verification on macOS and Windows, relying solely on package certificates leaves gaps if certificate authorities are compromised or if local configurations are manipulated.
We propose a multi-layered verification strategy that intersects with the auto-update lifecycle. Prior to allowing autoUpdater.quitAndInstall(), the app should perform a rigorous, secondary verify operation on the downloaded binary.
We can hook into the update pipeline to perform an out-of-band SHA256 checksum audit and binary signature verification against a known, signed metadata manifest.
import{autoUpdater}from'electron-updater';import{promisesasfs}from'fs';import*ascryptofrom'crypto';import{execFile}from'child_process';autoUpdater.on('update-downloaded',async(info)=>{constdownloadedFile=info.downloadedFile;if(!downloadedFile){console.error('Update downloaded but file path is missing.');return;}try{// 1. Perform SHA256 Checksum VerificationconstfileBuffer=awaitfs.readFile(downloadedFile);consthash=crypto.createHash('sha256').update(fileBuffer).digest('hex');// Fetch target hash from a signed, secure manifest hosted on a separate secure endpointconstexpectedHash=awaitfetchExpectedHashFromSignedManifest(info.version);if(hash!==expectedHash){thrownewError(`Checksum mismatch! Expected ${expectedHash}, got ${hash}`);}// 2. Perform Native Platform Signature CheckawaitverifyNativeSignature(downloadedFile);console.log('Update package verified successfully. Safe to install.');// Notify renderer that update is verified and readyrootWindow.webContents.send('update-downloaded',{verified: true,version: info.version});}catch(error){console.error('CRITICAL: Update package validation failed!',error);// Secure deletion of the invalid binary to prevent executionawaitfs.unlink(downloadedFile).catch(()=>{});}});// Platform-specific signature checksfunctionverifyNativeSignature(filePath: string): Promise<void>{returnnewPromise((resolve,reject)=>{if(process.platform==='win32'){// Use Windows PowerShell to verify digital signatureexecFile('powershell.exe',['-NoProfile','-NonInteractive','-Command',`Get-AuthenticodeSignature "${filePath}" | Where-Object { $_.Status -eq "Valid" }`],(err,stdout)=>{if(err||!stdout.trim()){reject(newError('Windows code signature validation failed.'));}else{resolve();}});}elseif(process.platform==='darwin'){// Use macOS codesign utility to verify developer ID signatureexecFile('codesign',['-v','--verbose=4',filePath],(err)=>{if(err){reject(newError('macOS codesign verification failed.'));}else{resolve();}});}else{// For Linux, verify package hash signatures if built with GPG signaturesresolve();}});}
4. CPU Idle Optimizations and Energy Efficiency
4.1. The Cost of Polling Loops
Currently, src/injected.ts (which is executed in the context of the main Rocket.Chat application page) relies on an active polling interval to setup reactive features:
setupReactiveFeatures();setInterval(setupReactiveFeatures,1000);// Check every second for newly loaded modules
Running a timer every 1000ms indefinitely—regardless of window focus, user activity, or system power state—is extremely inefficient. It forces Chromium's renderer process to wake up constantly, preventing the host CPU from entering low-power idle states. This degrades battery life on laptops.
4.2. Event-Driven Architecture with MutationObserver
Instead of polling, we should subscribe directly to structural modifications in the DOM or the React/Meteor root nodes using MutationObserver.
// Replacement for the active polling loop in src/injected.tsconstregisterObserver=()=>{consttargetNode=document.body;constconfig={childList: true,subtree: true};constcallback=(mutationsList: MutationRecord[])=>{letmoduleAdded=false;for(constmutationofmutationsList){if(mutation.type==='childList'){// Check if Meteor-related or target React/Tracker modules were addedconsthasReactRoots=Array.from(mutation.addedNodes).some((node)=>nodeinstanceofElement&&node.querySelector('[data-reactroot], #react-root'));if(hasReactRoots){moduleAdded=true;break;}}}if(moduleAdded){setupReactiveFeatures();}};constobserver=newMutationObserver(callback);observer.observe(targetNode,config);// Return disconnect handle for cleanupreturn()=>observer.disconnect();};
4.3. System Power State Aware Throttling
We can leverage Electron's powerMonitor API in the Main process to actively throttle background windows when the system enters an idle state or when the screen is locked/suspended.
import{powerMonitor,powerSaveBlocker}from'electron';// Track active background processes and throttlepowerMonitor.on('suspend',()=>{console.log('System is suspending. Throttling all background renderers.');throttleAllWindows(true);});powerMonitor.on('resume',()=>{console.log('System resumed. Restoring normal performance profile.');throttleAllWindows(false);});powerMonitor.on('lock-screen',()=>{console.log('Screen locked. Pausing non-essential tasks.');throttleAllWindows(true);});powerMonitor.on('unlock-screen',()=>{throttleAllWindows(false);});functionthrottleAllWindows(throttle: boolean){constwindows=BrowserWindow.getAllWindows();for(constwinofwindows){if(win.isDestroyed())continue;if(throttle){// Throttle rendering and background intervals completelywin.webContents.setFrameRate(10);// Throttle rendering to 10 FPSwin.webContents.send('power-state-change','idle');}else{win.webContents.setFrameRate(60);// Restore normal 60 FPS renderingwin.webContents.send('power-state-change','active');}}}
5. Implementation Roadmap
We propose rolling out these updates in incremental, low-risk phases:
RFC: Hardening Rocket.Chat.Electron's Security Posture and Enhancing CPU/Resource Efficiency
Status: Proposed
Author: Shevilll
Target: RocketChat/Rocket.Chat.Electron
Focus Areas: Security (Context Isolation & Secure Preloads), Supply Chain Security (Auto-Updater Verification), and Resource Optimization (CPU Idle States).
1. Executive Summary
As Rocket.Chat Desktop continues to serve millions of users globally across macOS, Windows, and Linux, modernizing its core architecture is critical to keeping pace with security standards and energy efficiency expectations.
This RFC proposes three critical, interconnected architectural upgrades to
Rocket.Chat.Electron:contextIsolation: falseandnodeIntegration: trueto a modern, zero-trust context-isolated environment viacontextBridgeacross all BrowserWindow targets (rootWindow,logViewerWindow,videoCallWindow).MutationObserversubscriptions and leveraging Electron'spowerMonitorAPI to put background tabs, rendering cycles, and event loops to sleep when idle.2. Secure-by-Default Isolation (Context Isolation & Preloads)
2.1. The Threat Model & Current Limitations
In the current setup, several critical windows—such as
rootWindowandlogViewerWindow—are configured with:If a Cross-Site Scripting (XSS) vulnerability is discovered within any local renderer or if untrusted markup is rendered (e.g., via HTML-based logs or shared views), an attacker gains full access to Node.js built-ins (
require('child_process'),require('fs')). This enables Remote Code Execution (RCE) directly on the user's host machine.By enforcing
contextIsolation: trueandnodeIntegration: false, the renderer process is separated from the preload script, protecting the Node.js runtime from exploit injection.2.2. Architectural Blueprint: The Secure Bridge
We propose a complete refactoring of the window instantiation preferences and IPC routing.
sequenceDiagram participant Renderer as Renderer Process (Web Content) participant Bridge as Context Bridge (Preload Script) participant Main as Main Process (Node.js) Renderer->>Bridge: Calls filtered API: RocketChatDesktop.send('log-action', data) Note over Bridge: Validates channel is allowed<br/>and sanitizes payload Bridge->>Main: ipcRenderer.send('log-action', sanitizedData) Note over Main: Executes Node.js logic safelyRefactored Window Instantiation (
src/ui/main/rootWindow.ts)Concrete Preload Implementation (
src/preload.ts)3. Auto-Updater Cryptographic Integrity Checks
3.1. Mitigating Update Spoofing & Supply Chain Attacks
While
electron-updaterperforms generic certificate verification on macOS and Windows, relying solely on package certificates leaves gaps if certificate authorities are compromised or if local configurations are manipulated.We propose a multi-layered verification strategy that intersects with the auto-update lifecycle. Prior to allowing
autoUpdater.quitAndInstall(), the app should perform a rigorous, secondary verify operation on the downloaded binary.3.2. Implementation Blueprint: Cryptographic Verification Hook
We can hook into the update pipeline to perform an out-of-band SHA256 checksum audit and binary signature verification against a known, signed metadata manifest.
4. CPU Idle Optimizations and Energy Efficiency
4.1. The Cost of Polling Loops
Currently,
src/injected.ts(which is executed in the context of the main Rocket.Chat application page) relies on an active polling interval to setup reactive features:Running a timer every 1000ms indefinitely—regardless of window focus, user activity, or system power state—is extremely inefficient. It forces Chromium's renderer process to wake up constantly, preventing the host CPU from entering low-power idle states. This degrades battery life on laptops.
4.2. Event-Driven Architecture with
MutationObserverInstead of polling, we should subscribe directly to structural modifications in the DOM or the React/Meteor root nodes using
MutationObserver.4.3. System Power State Aware Throttling
We can leverage Electron's
powerMonitorAPI in the Main process to actively throttle background windows when the system enters an idle state or when the screen is locked/suspended.5. Implementation Roadmap
We propose rolling out these updates in incremental, low-risk phases:
6. Feedback & Discussion
We welcome comments and feedback from core maintainers on: