sshs3 Docs
v0.9 sshs3.com ↗ GitHub ↗

Architecture, Security Model & Internals

Internals & Auditing Target Platforms: Architecture Reference Last Updated: 2026-10-05 20:50
Three-process Electron sandboxing, active Electron Fuses, threat model matrix, and autogenerated IPC contract reference.

Architecture, Security Model & System Internals

This chapter documents the internal architecture, multi-process isolation model, active Electron Fuses, and complete IPC contracts of sshs3. The IPC table is autogenerated directly from application source code (src/shared/types/ipc.ts) and is intended for security auditors, penetration testers, and systems engineers.


1. Three-Process Architecture & Sandboxing

sshs3 is built on Electron's multi-process model with strict separation of privilege between the presentation layer and system execution engines:

📊 Architecture Diagram
flowchart TD
    subgraph RendererProcess ["Renderer Process (Chromium Sandbox)"]
        ReactUI["React 18 Frontend (xterm.js, TabBar, DualPane)"]
        NoNode["nodeIntegration: false • contextIsolation: true"]
    end

    subgraph PreloadLayer ["Preload Layer (ContextBridge)"]
        MultiSSHApi["window.multissh (Strict Typed Facade)"]
        SafeIPC["ipcRenderer.invoke() / on()"]
    end

    subgraph MainProcess ["Main Process (Privileged Node.js)"]
        IpcBridge["IpcBridge.ts (Central IPC Router)"]
        PtyManager["SSHPtyManager (node-pty OpenSSH Engine)"]
        StorageEngine["OpenSSH SFTP v3 & AWS S3 SDK v3"]
        SecurityEngine["AskpassServer & AgentLifecycleManager"]
        Keyring["safeStorage (OS Keyring: libsecret / DPAPI / Keychain)"]
    end

    ReactUI --> MultiSSHApi
    MultiSSHApi --> SafeIPC
    SafeIPC --> IpcBridge
    IpcBridge --> PtyManager
    IpcBridge --> StorageEngine
    IpcBridge --> SecurityEngine
    IpcBridge --> Keyring

Architectural Security Guarantees

  1. Zero Node.js Access in Renderer: The user interface has zero direct access to Node.js primitives (fs, child_process, net, electron). All operations must navigate the typed IPC contract.
  2. Fail-Closed Security Design: If the user interface unmounts or fails to respond to host key validation (TOFU) or PIN prompts within the timeout window, the operation aborts automatically.
  3. Atomic Persistence: All internal state stores (ProfileStore, SettingsStore, SessionStore) employ sequential queueMutation promises to ensure atomic disk writes via temporary files.
  4. App-Wide AppAgent & Concurrent Agent Lifecycle: AgentLifecycleManager probes for a running agent via ensureAgent(). Concurrent startup callers (such as restored local shell tabs racing startup initialization) coalesce onto the same in-flight promise to prevent PTY environment race conditions. In Global PIN caching mode, the app runs a single app-wide agent (AppAgent) with a stable socket ($XDG_RUNTIME_DIR/sshs3/agent.sock or /tmp/sshs3-agent-/agent.sock, 0700), exposed to external terminals via a serialized, injection-safe # BEGIN sshs3-agent block in ~/.ssh/config.

2. Electron Fuses & Binary Hardening

During production packaging, hardware-level Electron Fuses are enforced via electron-builder.json:

Electron FuseStatusSecurity Rationale
runAsNodeEnabled (Restricted)Required for internal auxiliary processes (askpass, certWorker.cjs, proxy CLI) to execute through the signed binary via ELECTRON_RUN_AS_NODE=1.
enableNodeCliInspectArgumentsDisabled (Locked)Prevents an attacker from attaching a debugger (--inspect, --inspect-brk) to the main process to inspect memory.
enableNodeOptionsEnvironmentVariableDisabled (Locked)Blocks arbitrary code injection via the NODE_OPTIONS environment variable.
onlyLoadAppFromAsarEnabled (Locked)Forces Electron to execute exclusively from inside the packaged app.asar archive.

3. Threat Model & Asset Protection Matrix

Asset / SecretStorage LocationIn-Memory LifetimeProtection Mechanism
Private SSH KeysHardware Token / DiskNever in app memoryZero Private Key Extraction. OpenSSH executes signing on the hardware chip or system PTY.
Smartcard PINsEphemeral in AskpassServerEphemeral (seconds to session)Purged immediately after handshake in Always Prompt mode. Never written to disk.
Saved Profile Passwordsprofiles.json on diskDecrypted only at connect timeEncrypted with AES via Electron safeStorage (libsecret on Linux, DPAPI on Windows, Keychain on macOS).
Remote Vault ProfilesRemote S3 / SFTP serverLifetime of sync sessionClient-side encrypted with AES-256-GCM and scrypt. Remote server sees only opaque ciphertext.
Forwarded X11 WindowsVcXsrv TCP Port 6000Lifetime of sessionAccess control enforced; requires MIT-MAGIC-COOKIE. Unauthorized LAN devices are rejected.

4. Complete Autogenerated IPC Channel Reference

Note

The table below is autogenerated directly from the application source code (src/shared/types/ipc.ts) during every documentation build. It enumerates all typed channels between the renderer and main process.

IPC ConstantChannel StringSubsystem Module
TERMINAL_CREATEterminal:createTerminal
TERMINAL_WRITEterminal:writeTerminal
TERMINAL_RESIZEterminal:resizeTerminal
TERMINAL_KILLterminal:killTerminal
TERMINAL_RECONNECTterminal:reconnectTerminal
TERMINAL_DATAterminal:dataTerminal
TERMINAL_EXITterminal:exitTerminal
TERMINAL_RECONNECTINGterminal:reconnectingTerminal
SMARTCARD_DETECTsmartcard:detectSmartcard
SMARTCARD_VALIDATEsmartcard:validateSmartcard
SMARTCARD_AGENT_PATH_STATUSsmartcard:agent-path-statusSmartcard
SMARTCARD_AGENT_PATH_FIXsmartcard:agent-path-fixSmartcard
SMARTCARD_LOCK_ALLsmartcard:lock-allSmartcard
SMARTCARD_LIST_CACHEDsmartcard:list-cachedSmartcard
SMARTCARD_UNLOCK_AT_STARTUPsmartcard:unlock-at-startupSmartcard
SMARTCARD_UNLOCK_NOWsmartcard:unlock-nowSmartcard
SMARTCARD_STARTUP_UNLOCK_STATUSsmartcard:startup-unlock-statusSmartcard
ASKPASS_PROMPTaskpass:promptSmartcard
ASKPASS_SUBMIT_PINaskpass:submit-pinSmartcard
PRESENCE_PROMPTpresence:promptSmartcard
PRESENCE_CLEARpresence:clearSmartcard
FIDO2_GENERATE_KEYfido2:generate-keySmartcard
FIDO2_LIST_RESIDENT_KEYSfido2:list-resident-keysSmartcard
FIDO2_DELETE_RESIDENT_KEYfido2:delete-resident-keySmartcard
HOSTKEY_PROMPThostkey:promptSFTP host key verification (TOFU)
HOSTKEY_RESPONDhostkey:respondSFTP host key verification (TOFU)
STORAGE_CONNECTstorage:connectStorage
STORAGE_DISCONNECTstorage:disconnectStorage
STORAGE_LISTstorage:listStorage
STORAGE_STATstorage:statStorage
STORAGE_CREATE_FOLDERstorage:create-folderStorage
STORAGE_DELETEstorage:deleteStorage
STORAGE_RENAMEstorage:renameStorage
STORAGE_CHMODstorage:chmodStorage
STORAGE_SET_METADATAstorage:set-metadataStorage
STORAGE_GET_TAGSstorage:get-tagsStorage
STORAGE_SET_TAGSstorage:set-tagsStorage
STORAGE_GET_BUCKET_POLICYstorage:get-bucket-policyStorage
STORAGE_SET_BUCKET_POLICYstorage:set-bucket-policyStorage
STORAGE_GET_BUCKET_CORSstorage:get-bucket-corsStorage
STORAGE_SET_BUCKET_CORSstorage:set-bucket-corsStorage
STORAGE_GET_BUCKET_VERSIONINGstorage:get-bucket-versioningStorage
STORAGE_SET_BUCKET_VERSIONINGstorage:set-bucket-versioningStorage
STORAGE_LIST_OBJECT_VERSIONSstorage:list-object-versionsStorage
STORAGE_DELETE_OBJECT_VERSIONstorage:delete-object-versionStorage
STORAGE_RESTORE_OBJECT_VERSIONstorage:restore-object-versionStorage
STORAGE_GET_PRESIGNED_URLstorage:get-presigned-urlStorage
STORAGE_GET_HOMEDIRstorage:get-homedirStorage
TRANSFER_ADDtransfer:addTransfer
TRANSFER_PAUSEtransfer:pauseTransfer
TRANSFER_RESUMEtransfer:resumeTransfer
TRANSFER_CANCELtransfer:cancelTransfer
TRANSFER_GET_JOBStransfer:get-jobsTransfer
TRANSFER_CLEAR_COMPLETEDtransfer:clear-completedTransfer
TRANSFER_PROGRESStransfer:progressTransfer
TRANSFER_CONFLICT_PROMPTtransfer:conflict-promptTransfer
TRANSFER_CONFLICT_RESPONDtransfer:conflict-respondTransfer
START_DRAGdrag:startTransfer
QUIT_CONFIRM_PROMPTapp:quit-confirm-promptQuit confirmation (renders the app's own themed dialog instead of a native OS message box)
QUIT_CONFIRM_RESPONDapp:quit-confirm-respondQuit confirmation (renders the app's own themed dialog instead of a native OS message box)
PROFILES_GETprofiles:getProfiles
PROFILES_SAVE_SSHprofiles:save-sshProfiles
PROFILES_DELETE_SSHprofiles:delete-sshProfiles
PROFILES_SAVE_S3profiles:save-s3Profiles
PROFILES_DELETE_S3profiles:delete-s3Profiles
PROFILES_SAVE_FOLDERprofiles:save-folderProfiles
PROFILES_DELETE_FOLDERprofiles:delete-folderProfiles
PROFILES_RENAME_FOLDERprofiles:rename-folderProfiles
PROFILES_IMPORT_SSH_CONFIGprofiles:import-ssh-configProfiles
PROFILES_EXPORT_JSONprofiles:export-jsonProfiles
PROFILES_IMPORT_JSONprofiles:import-jsonProfiles
SESSION_GETsession:getSession & Tabs
SESSION_SAVEsession:saveSession & Tabs
CLIPBOARD_HISTORY_LISTclipboardHistory:listSession & Tabs
CLIPBOARD_HISTORY_ADDclipboardHistory:addSession & Tabs
CLIPBOARD_HISTORY_DELETEclipboardHistory:deleteSession & Tabs
CLIPBOARD_HISTORY_CLEARclipboardHistory:clearSession & Tabs
SNIPPETS_LISTsnippets:listSession & Tabs
SNIPPETS_SAVEsnippets:saveSession & Tabs
SNIPPETS_DELETEsnippets:deleteSession & Tabs
SETTINGS_GETsettings:getSettings
SETTINGS_SAVEsettings:saveSettings
PROFILE_SYNC_SETUPprofile-sync:setupbetween their own machines via a Zero-Knowledge-encrypted S3/SFTP target.)
PROFILE_SYNC_ENABLEprofile-sync:enablebetween their own machines via a Zero-Knowledge-encrypted S3/SFTP target.)
PROFILE_SYNC_PUSHprofile-sync:pushbetween their own machines via a Zero-Knowledge-encrypted S3/SFTP target.)
PROFILE_SYNC_PULLprofile-sync:pullbetween their own machines via a Zero-Knowledge-encrypted S3/SFTP target.)
PROFILE_SYNC_STATUSprofile-sync:statusbetween their own machines via a Zero-Knowledge-encrypted S3/SFTP target.)
PROFILE_SYNC_COMPAREprofile-sync:comparebetween their own machines via a Zero-Knowledge-encrypted S3/SFTP target.)
PROFILE_SYNC_SET_AUTO_SYNCprofile-sync:set-auto-syncbetween their own machines via a Zero-Knowledge-encrypted S3/SFTP target.)
PROFILE_SYNC_UNLOCK_SMARTCARDprofile-sync:unlock-smartcardbetween their own machines via a Zero-Knowledge-encrypted S3/SFTP target.)
PROFILE_SYNC_LINK_SMARTCARDprofile-sync:link-smartcardbetween their own machines via a Zero-Knowledge-encrypted S3/SFTP target.)
PROFILE_SYNC_UNLINK_SMARTCARDprofile-sync:unlink-smartcardbetween their own machines via a Zero-Knowledge-encrypted S3/SFTP target.)
PROFILE_SYNC_WIPEprofile-sync:wipebetween their own machines via a Zero-Knowledge-encrypted S3/SFTP target.)
CONNECTION_TEST_SSHconnection:test-sshConnection Testing
SSH_LIST_PUBLIC_KEYSssh:list-public-keysInstall public keys in a host's authorized_keys (ssh-copy-id)
SSH_INSTALL_PUBLIC_KEYSssh:install-public-keysInstall public keys in a host's authorized_keys (ssh-copy-id)
SSH_PROBE_HOSTssh:probe-hostInstall public keys in a host's authorized_keys (ssh-copy-id)
SSH_TEST_LOGINssh:test-loginInstall public keys in a host's authorized_keys (ssh-copy-id)
SSH_BUILD_INSTALL_COMMANDssh:build-install-commandInstall public keys in a host's authorized_keys (ssh-copy-id)
CONNECTION_TEST_S3connection:test-s3Install public keys in a host's authorized_keys (ssh-copy-id)
AWS_SSO_LOGINaws-sso:loginAWS SSO login (device-authorization flow)
AWS_SSO_LOGIN_CANCELaws-sso:login-cancelAWS SSO login (device-authorization flow)
AWS_SSO_PROMPTaws-sso:promptAWS SSO login (device-authorization flow)
AWS_SSO_LIST_ACCOUNTSaws-sso:list-accountsAWS SSO login (device-authorization flow)
AWS_SSO_LIST_ROLESaws-sso:list-rolesAWS SSO login (device-authorization flow)
GIT_FETCH_PUBLIC_KEYSgit:fetch-public-keysGit & Git Provider Integration
GIT_GET_SIGNING_CONFIGgit:get-signing-configGit & Git Provider Integration
GIT_CONFIGURE_SIGNINGgit:configure-signingGit & Git Provider Integration
GIT_SET_SIGNING_ENABLEDgit:set-signing-enabledGit & Git Provider Integration
GIT_GET_STATUSgit:get-statusGit & Git Provider Integration
GIT_CLONEgit:cloneGit & Git Provider Integration
GIT_PULLgit:pullGit & Git Provider Integration
GIT_TEST_REMOTE_ACCESSgit:test-remote-accessGit & Git Provider Integration
DOTFILES_IMPORT_FROM_GITdotfiles:import-from-gitGit & Git Provider Integration
SSH_AGENT_STATUSssh:agent-statusSSH Agent
DOTFILES_POOLS_GETdotfiles:pools-getDotfiles pools (opt-in, see AppSettings.dotfilesPoolEnabled)
DOTFILES_POOLS_SAVEdotfiles:pools-saveDotfiles pools (opt-in, see AppSettings.dotfilesPoolEnabled)
DOTFILES_POOLS_DELETEdotfiles:pools-deleteDotfiles pools (opt-in, see AppSettings.dotfilesPoolEnabled)
DOTFILES_OPEN_FOLDERdotfiles:open-folderDotfiles pools (opt-in, see AppSettings.dotfilesPoolEnabled)
DOTFILES_SELECT_FILESdotfiles:select-filesDotfiles pools (opt-in, see AppSettings.dotfilesPoolEnabled)
DOTFILES_READ_SOURCESdotfiles:read-sourcesDotfiles pools (opt-in, see AppSettings.dotfilesPoolEnabled)
DOTFILES_ADD_FROM_STORAGEdotfiles:add-from-storageDotfiles pools (opt-in, see AppSettings.dotfilesPoolEnabled)
DOTFILES_SYNC_PROMPTdotfiles:sync-promptDotfiles pools (opt-in, see AppSettings.dotfilesPoolEnabled)
DOTFILES_SYNC_RESPONDdotfiles:sync-respondDotfiles pools (opt-in, see AppSettings.dotfilesPoolEnabled)
DOTFILES_SYNC_STATUSdotfiles:sync-statusDotfiles pools (opt-in, see AppSettings.dotfilesPoolEnabled)
FILE_READfile:readFile Editor
FILE_SAVEfile:saveFile Editor
FILE_OPEN_EXTERNALfile:open-externalFile Editor
FILE_CLOSE_EXTERNALfile:close-externalFile Editor
FILE_EXTERNAL_STATUSfile:external-statusFile Editor
FILE_TAIL_STARTfile:tail:startFile Editor
FILE_TAIL_STOPfile:tail:stopFile Editor
FILE_TAIL_DATAfile:tail:dataFile Editor
FILE_TAIL_ERRORfile:tail:errorFile Editor
SEARCH_STARTsearch:startContent search ("search inside files")
SEARCH_CANCELsearch:cancelContent search ("search inside files")
SEARCH_PREVIEWsearch:previewContent search ("search inside files")
SEARCH_RESULTsearch:resultContent search ("search inside files")
SEARCH_PROGRESSsearch:progressContent search ("search inside files")
SEARCH_ERRORsearch:errorContent search ("search inside files")
SEARCH_DONEsearch:doneContent search ("search inside files")
APP_OPEN_EXTERNALapp:open-externalGeneral
APP_GET_VERSIONapp:get-versionGeneral
UPDATE_GET_STATEupdate:get-stateGeneral
UPDATE_CHECKupdate:checkGeneral
UPDATE_DOWNLOADupdate:downloadGeneral
UPDATE_INSTALLupdate:installGeneral
UPDATE_STATEupdate:stateGeneral
APP_GET_HOMEDIRapp:get-homedirGeneral
APP_GET_PLATFORMapp:get-platformGeneral
APP_GET_HOSTNAMEapp:get-hostnameGeneral
APP_GET_SECURITY_STATUSapp:get-security-statusGeneral
APP_DETECT_LOCAL_SHELLSapp:detect-local-shellsGeneral
APP_CHECK_X11_SERVERapp:check-x11-serverGeneral
X11_GET_STATUSx11:get-statusGeneral
X11_START_SERVERx11:start-serverGeneral
X11_STOP_SERVERx11:stop-serverGeneral
DIALOG_OPEN_FILEdialog:open-fileGeneral
DIALOG_OPEN_FOLDERdialog:open-folderGeneral
DIALOG_SAVE_FILEdialog:save-fileGeneral
DIR_SYNC_COMPUTE_DIFFdirsync:compute-diffDirectory sync (dual-pane folder → folder diff/copy between any two storage providers)
DIR_SYNC_SCAN_PROGRESSdirsync:scan-progressDirectory sync (dual-pane folder → folder diff/copy between any two storage providers)
DIR_SYNC_APPLYdirsync:applyDirectory sync (dual-pane folder → folder diff/copy between any two storage providers)
DIR_SYNC_APPLY_PROGRESSdirsync:apply-progressDirectory sync (dual-pane folder → folder diff/copy between any two storage providers)
DIR_SYNC_PROFILE_LISTdirsync:profile-listDirectory sync (dual-pane folder → folder diff/copy between any two storage providers)
DIR_SYNC_PROFILE_SAVEdirsync:profile-saveDirectory sync (dual-pane folder → folder diff/copy between any two storage providers)
DIR_SYNC_PROFILE_DELETEdirsync:profile-deleteDirectory sync (dual-pane folder → folder diff/copy between any two storage providers)
K8S_LIST_CONTEXTSk8s:list-contextsKubernetes / OpenShift discovery
K8S_LIST_NAMESPACESk8s:list-namespacesKubernetes / OpenShift discovery
K8S_LIST_PODSk8s:list-podsKubernetes / OpenShift discovery
K8S_RELOADk8s:reloadKubernetes / OpenShift discovery
K8S_LOGINk8s:loginKubernetes / OpenShift discovery
K8S_CONFIG_CHANGEDk8s:config-changedKubernetes / OpenShift discovery
K8S_TERMINAL_CREATEk8s-terminal:createKubernetes / OpenShift interactive exec terminal
K8S_TERMINAL_WRITEk8s-terminal:writeKubernetes / OpenShift interactive exec terminal
K8S_TERMINAL_RESIZEk8s-terminal:resizeKubernetes / OpenShift interactive exec terminal
K8S_TERMINAL_KILLk8s-terminal:killKubernetes / OpenShift interactive exec terminal
PERF_SSH_SAMPLEperf:ssh-sampleKubernetes / OpenShift interactive exec terminal
PERF_K8S_SAMPLEperf:k8s-sampleKubernetes / OpenShift interactive exec terminal
PERF_LOCAL_SAMPLEperf:local-sampleKubernetes / OpenShift interactive exec terminal
K8S_TERMINAL_DATAk8s-terminal:dataKubernetes / OpenShift interactive exec terminal
K8S_TERMINAL_EXITk8s-terminal:exitKubernetes / OpenShift interactive exec terminal
K8S_LOG_STARTk8s-log:startKubernetes / OpenShift log follow
K8S_LOG_STOPk8s-log:stopKubernetes / OpenShift log follow
K8S_LOG_DATAk8s-log:dataKubernetes / OpenShift log follow
K8S_LOG_ENDk8s-log:endKubernetes / OpenShift log follow
K8S_POD_DESCRIBEk8s:pod-describeKubernetes / OpenShift pod describe & details
K8S_PORT_FORWARD_STARTk8s-port-forward:startKubernetes / OpenShift port forward
K8S_PORT_FORWARD_STOPk8s-port-forward:stopKubernetes / OpenShift port forward
K8S_PORT_FORWARD_LISTk8s-port-forward:listKubernetes / OpenShift port forward
K8S_PORT_FORWARD_EVENTk8s-port-forward:eventKubernetes / OpenShift port forward
K8S_DEBUG_ATTACHk8s:debug-attachKubernetes / OpenShift debug
SSH_TUNNEL_STARTssh-tunnel:startSSH tunnels (standalone port forwarding, independent of terminal sessions)
SSH_TUNNEL_STOPssh-tunnel:stopSSH tunnels (standalone port forwarding, independent of terminal sessions)
SSH_TUNNEL_LISTssh-tunnel:listSSH tunnels (standalone port forwarding, independent of terminal sessions)
SSH_TUNNEL_EVENTssh-tunnel:eventSSH tunnels (standalone port forwarding, independent of terminal sessions)
SSH_TUNNEL_CHECK_PORTssh-tunnel:check-portSSH tunnels (standalone port forwarding, independent of terminal sessions)

5. Troubleshooting & Diagnostics Runbook

Symptom / Error MessageProbable Root CauseCorrective Action
IPC channel not registeredVersion mismatch between renderer and mainVerify IpcBridge.ts registers a handler matching the channel constant.
safeStorage is not availableOperating system keyring service is not runningIn headless Linux setups, ensure gnome-keyring or a compatible Secret Service daemon is active.
ELECTRON_RUN_AS_NODE rejectedBinary fuses were modified or corruptedValidate binary fuses using npx @electron/fuses read --app .