Security — threat model

This page lays out what obsidian-remote-ssh defends against and what it doesn’t. If you’re operating in a higher-threat environment than the model assumes, you’ll want extra defences.

Trust boundaries

graph TB
  subgraph Local["Local machine (your desktop)"]
    OB[Obsidian]
    PL[Plugin]
    KEY["~/.ssh/id_ed25519 (private key)"]
  end
  subgraph Wire["SSH transport"]
    SSH[SSH session]
  end
  subgraph Remote["Remote host (your trust)"]
    SSHD[sshd]
    DAEM[Daemon]
    VAULT[Vault files]
  end
  PL -.uses.-> KEY
  PL --> SSH
  SSH --> SSHD
  SSHD --> DAEM
  DAEM --> VAULT

What we defend against

ThreatDefense
Network eavesdroppingAll RPC + file content is inside the SSH session — same crypto as ssh itself
Remote login by an attackerStandard SSH keys + your sshd’s hardening (no plugin-specific extra surface)
Wrong host key (MITM, hostile DNS)Plugin maintains its own known-host store; mismatch on a known host requires explicit override
Corrupted daemon binary on the wireSHA256 round-trip after SFTP upload; mismatch fails the deploy
Tampered daemon binary at rest (you downloaded it from a third-party mirror)Cosign verify proves it came from THIS repo’s release pipeline
Plugin reading files outside the configured vaultDaemon refuses any path containing .. or escaping the vault root via symlink (PathOutsideVault)
Token theft via shared filesystemToken written mode 0600 under the daemon’s home; only that user can read it
Concurrent edit conflictsPer-write expectedMtime precondition; conflict surfaces as a UI prompt, not a silent overwrite

What we DON’T defend against

ThreatWhy
Compromised remote OSIf the remote is fully owned, the daemon is too — anything reading the vault from the daemon’s perspective is fair game. Defence is your remote’s hardening (sshd, firewall, OS updates).
Compromised local machineIf your local OS is owned, your SSH keys + plugin settings are too. The plugin doesn’t add extra at-rest encryption; it relies on your OS’s user account isolation.
Malicious sshd intercepting in real timeIf you’re worried about this, you’ve got bigger problems than this plugin can solve. The plugin’s host-key store catches static MITM (cert swap); it does not catch a fully colluding sshd that can answer correctly during the verification round trip.
Side-channels on the host (other users reading the vault directory)The daemon runs under your user; vault file permissions are whatever you set them to (typically 0644 / 0755). Use OS-level ACLs / encryption-at-rest for shared hosts.

Defence-in-depth recommendations

RiskMitigation
Untrusted networksUse Tailscale / WireGuard / a Cloudflare Tunnel as the transport bottom layer; SSH then runs inside the tunnel
Lost laptopDisk encryption (FileVault, BitLocker, LUKS) — protects the SSH key + vault shadow
Long-lived agent forwardingThe plugin doesn’t use agent forwarding for chained jumps — each hop authenticates independently. Don’t enable it elsewhere unless you must.
Daemon binary supply chainVerify the bundled binary with cosign (see Cosign verify) before pre-deploying via systemd; the auto-deploy path also SHA256-verifies post-upload but verifies less than a cosign check

Reporting vulnerabilities

GitHub Security Advisories: obsidian-remote-ssh/security/advisories/new. Coordinated disclosure preferred. See the Cosign verify page for what a “patched release” looks like operationally.

Next: Cosign verify.