Restrict renderer IPC to an explicit method allowlist

This commit is contained in:
Avi 2026-08-21 13:30:58 -05:00
commit 4bde3957b9

View file

@ -113,6 +113,46 @@ async function backendRequest(method: string, params: Record<string, unknown>):
return response; return response;
} }
/**
* Methods the renderer is allowed to invoke, enforced in the main process so a
* compromised page cannot invent new backend calls. Everything else is
* rejected. Sensitive methods are listed because their screens need them; they
* remain gated by the vault password on the backend side.
*/
const RENDERER_METHODS: ReadonlySet<string> = new Set([
// Handled natively by Electron main (dialogs, HTTP).
'pick_image',
'link_preview',
'upload_image',
// Forwarded to the Rust backend over stdio.
'init',
'get_state',
'create_profile',
'select_profile',
'publish_note',
'feed_get',
'relay_add',
'relay_remove',
'relay_set_enabled',
'relay_test',
'settings_update',
'backup_now',
'set_vault_password',
'unlock_vault',
'lock_vault',
'remove_vault_password',
'reveal_secret_key',
'signer_connect',
'signer_disconnect',
'signer_status',
'signer_approve',
]);
/** True when `method` may be dispatched. Unknown methods never reach the backend. */
function isAllowedMethod(method: unknown): method is string {
return typeof method === 'string' && RENDERER_METHODS.has(method);
}
const IMAGE_EXTENSIONS = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'avif']; const IMAGE_EXTENSIONS = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'avif'];
/** How long to wait for a link-preview page before giving up. */ /** How long to wait for a link-preview page before giving up. */
@ -346,6 +386,15 @@ app.whenReady().then(() => {
ipcMain.handle( ipcMain.handle(
'backend:request', 'backend:request',
async (_event, payload: { method: string; params?: Record<string, unknown> }) => { async (_event, payload: { method: string; params?: Record<string, unknown> }) => {
if (!isAllowedMethod(payload?.method)) {
console.warn('[backend] rejected renderer method:', String(payload?.method));
return {
status: 'error',
code: 'unknown_method',
message: 'That operation is not permitted.',
details: null,
};
}
const params = payload.params ?? {}; const params = payload.params ?? {};
// Media and network tasks are handled here (Electron) rather than the // Media and network tasks are handled here (Electron) rather than the
// Rust backend: they need a native file dialog, the hosting upload, and // Rust backend: they need a native file dialog, the hosting upload, and