From f823c042e3c2f6b385463aa34216ab1a482f4c2d Mon Sep 17 00:00:00 2001 From: Local Dev Date: Sun, 4 Oct 2026 04:22:41 +0200 Subject: [PATCH] Theseus: wallet-imports and Hermes IPC only answer their own pages wallet-imports-signer hands out raw seeds and WIFs while the vault is open, and hermes-* sends and reads the user's Nostr messages; none of these handlers checked who was asking. No preload exposes the wallet-imports channels (add-ons use the vaultImports shim), so they are now Settings-only like the password channels; the Hermes channels answer only the Messages window. --- main.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/main.js b/main.js index ecbe9833..0772bbda 100644 --- a/main.js +++ b/main.js @@ -872,7 +872,14 @@ const SETTINGS_ONLY = new Set([ "recheck-update", "remove-from-list", "set-engine-enabled", "set-engine-order", "settings-open-panel", "settings-section", "tor-state", "vault-pin-clear", "vault-pin-set", "vault-pin-status", "vault-pin-unlock", + // Raw seeds and WIFs. No page uses these (add-ons go through the + // vaultImports shim in main), but an unguarded handler is reachable by any + // renderer that gets code execution. + "wallet-imports-add", "wallet-imports-list", "wallet-imports-remove", "wallet-imports-signer", ]); +// Hermes (Nostr messaging) speaks as the user and reads their messages: +// only its own window may drive it. +const HERMES_ONLY = new Set(["hermes-status", "hermes-init", "hermes-can-use-vault", "hermes-close", "hermes-inbox", "hermes-send"]); const SETTINGS_SHARED = new Set([ "add-engine", "addons-apply-staged", "addons-list-staged", "app-restart", "collision-state", "remove-engine", "settings-get", "settings-set", "toggle-tor", @@ -883,7 +890,12 @@ function isSettingsPage(sender) { { const handle = ipcMain.handle.bind(ipcMain); ipcMain.handle = (channel, fn) => handle(channel, - SETTINGS_ONLY.has(channel) || SETTINGS_SHARED.has(channel) + HERMES_ONLY.has(channel) + ? (e, ...args) => { + if (!hermesWin || hermesWin.isDestroyed() || e.sender !== hermesWin.webContents) throw new Error(`${channel}: messages window only`); + return fn(e, ...args); + } + : SETTINGS_ONLY.has(channel) || SETTINGS_SHARED.has(channel) ? (e, ...args) => { const ok = isSettingsPage(e.sender) || (SETTINGS_SHARED.has(channel) && chrome && e.sender === chrome.webContents); if (!ok) throw new Error(`${channel}: settings only`);