Skip to content

Host Key Verification

Every SSH server proves its identity with a host key — a cryptographic key pair that only that server holds the private half of. Host key verification is what stops you from unknowingly typing your password or handing your session to an impostor sitting between you and the real server. ZestSSH checks the host key on every connection and keeps a record of the keys you have trusted, so it can tell you the moment something changes.

Think of it like recognising a friend’s voice on the phone. The first time they call from a new number you take it on faith that it is really them. Every call after that, you expect the same voice — and if a stranger’s voice answers instead, that is your cue to stop and check before you say anything sensitive.

Host key verification is a free feature. It works identically on every tier and cannot be turned off for changed keys.

ZestSSH uses the standard SSH trust model, trust-on-first-use:

  1. First connection — The server presents its host key. ZestSSH has never seen this host before, so it asks you to confirm the key before continuing. Once you accept, the key’s fingerprint is saved.
  2. Every connection after — ZestSSH re-checks the presented key against the saved one. If they match, the connection proceeds silently. If they differ, you get a loud warning.

The trusted keys live in a known-hosts store inside ZestSSH’s encrypted database — the same SQLCipher-encrypted Drift database that holds your connections and other data. It is not a plaintext ~/.ssh/known_hosts file on disk.

Each trusted key is one row in the known-hosts store:

FieldMeaning
hostThe server address, canonicalised (see below)
portThe SSH port
keyTypeThe host-key algorithm, e.g. ssh-ed25519, ssh-rsa, ecdsa-sha2-nistp256
fingerprintThe SHA-256 fingerprint of the key
publicKeyBase64The full host public key, so future keys can be compared exactly
firstSeenWhen you first trusted this key — this is the “trusted on” date shown in warnings
lastSeenUpdated to the current time on every successful match

Canonicalisation: one host, one trust record

Section titled “Canonicalisation: one host, one trust record”

Before any lookup, ZestSSH normalises the host string and key type so that cosmetically different spellings of the same server resolve to a single trust record:

  • Hosts are lowercased and trimmed, a trailing FQDN dot is stripped (Example.com. -> example.com), and IPv6 literal brackets are removed ([::1] -> ::1).
  • RSA signature-algorithm aliases (rsa-sha2-256, rsa-sha2-512) collapse to the underlying ssh-rsa key type.

Without this, an attacker — or just an inconsistent config — could force a fresh “new host” prompt for a server you had already trusted, by presenting it under a slightly different name or signature algorithm. Collapsing the variants closes that gap.

If the presented key matches your saved fingerprint, the connection continues with no interruption. ZestSSH quietly updates the lastSeen timestamp and moves on. This is the case the overwhelming majority of the time.

On a first connection ZestSSH shows the routine first-connection prompt with the key’s fingerprint, and you choose whether to trust it. When you accept, the key is written to the known-hosts store.

You can turn the new-host prompt off in settings. With it off, new keys are trusted automatically and a brief toast tells you it happened, so a silently-trusted key is never invisible. Changed keys always prompt regardless of this setting — there is no way to auto-accept a key that replaced a previously trusted one.

Automation runs headlessly and has no UI to prompt. On the Automation Engine path, new hosts are auto-trusted, but a changed host key is rejected outright as a possible MITM.

This is the security-critical case. A key ZestSSH has on record no longer matches the key the server just presented. ZestSSH treats two situations as a change:

  • Fingerprint mismatch — the same key type, but a different key.
  • Key-type change — the host is known under one algorithm (say ssh-rsa) but now answers with a different one (say ssh-ed25519) that has no matching trust record. ZestSSH fails closed here rather than treating it as a brand-new host, because a mismatched type is exactly how an attacker would try to slip past a type-scoped check.

A changed key has a benign explanation more often than not — the server was rebuilt, its host keys were regenerated, or a different machine now answers at that address. But it is also precisely what a man-in-the-middle attack looks like, so ZestSSH never decides for you.

When a change is detected, ZestSSH always stops and shows a dedicated warning dialog. It is deliberately built to look and behave differently from the calm first-connection prompt:

  • A warning banner names the server and explains, in plain language, both the benign causes and the malicious one — neither is buried.

  • Both fingerprints are shown side by side: the Expected key with the date you first trusted it (“Expected — trusted 2026-08-01 14:32”), and the Received now key in a danger-tinted box.

  • If the previously trusted key predates fingerprint storage, the expected side honestly says the trust date is unknown or the old key cannot be shown, rather than inventing a value.

  • A copyable, ready-to-run verification command is included — tailored to the received key type — that you can run on the server itself to print its own host-key fingerprint for an out-of-band comparison. For example:

    ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

    For an unrecognised key type it falls back to printing every host key’s fingerprint.

  • A note reminds you that trusting the new key permanently replaces the key saved for this host.

Crucially, the actions are inverted compared to the first-connection prompt. Cancel and disconnect is the prominent, autofocused button, so both muscle memory and the Enter key land on the safe choice. Trust new key is the quiet, warning-toned secondary that you have to reach for deliberately. Dismissing the dialog any other way (tapping outside it, backing out) also aborts the connection. The connection only proceeds if you explicitly choose to trust the new key.

Detecting a change also marks the host so you cannot forget about it. The moment a change is detected, ZestSSH records the host:port as having an unresolved changed key. From then on the host’s card carries a red Key changed badge (or a compact red dot on small cards), with a tooltip explaining the warning.

That badge is sticky by design:

  • It is set as soon as the change is detected — you see it even without opening a session again.
  • Cancelling or aborting the connection leaves it in place. The card keeps warning you.
  • It is cleared only when you explicitly trust the new key.

The unresolved-change flag is stored per-device (it is transient security UX, not synced app data), so resolving it on one device does not silence the warning on another until that device sees the key for itself.

If you have verified out-of-band that the new key is legitimate — for example the fingerprint from ssh-keygen -lf on the server matches the “Received now” fingerprint — choose Trust new key. ZestSSH then:

  1. Replaces the stored key for this host with the new one (updating its fingerprint and public key).
  2. Clears the “Key changed” badge from the host card.
  3. Continues the connection.

If you are not sure, choose Cancel and disconnect and investigate first. Do not trust a changed key just to make the warning go away.

Host key verification is on by default and needs no setup, but here is what you can control:

  1. Open Settings > Security.
  2. Under host key handling, toggle whether ZestSSH prompts before trusting a new host. Off means new keys are auto-trusted (with a toast); changed keys still always prompt.
  3. To review or remove trusted keys, open the known-hosts list from settings. Deleting a host’s entry resets it to first-use, so the next connection re-prompts.
CapabilityFreeSqueezed (Pro)Juiced
Trust-on-first-use verificationYesYesYes
Always-on changed-key warningYesYesYes
Persistent changed-key badgeYesYesYes
Out-of-band verify command in the warningYesYesYes

Host key verification is core security and is identical on every tier — it is never paywalled.

  • Clicking through the changed-key warning out of habit. The dialog inverts its buttons and autofocuses “Cancel” precisely so a reflexive Enter does not trust an attacker’s key. Slow down and read both fingerprints.
  • Assuming a changed key is always an attack. Rebuilt servers and regenerated host keys are common and benign. Verify out-of-band before you decide — do not panic, and do not blindly trust.
  • Verifying against the wrong source. Comparing the app’s fingerprint to another value shown by the same potentially-compromised channel proves nothing. Use a genuinely independent path: a console session, your provider’s dashboard, or the ssh-keygen -lf command run directly on the server.
  • Ignoring the red badge. A host card showing “Key changed” means an unresolved warning is waiting. It will not clear itself — resolve it deliberately by trusting the verified key, or by not connecting.
  • Deleting a known-host entry to “fix” a warning. That just resets the host to first-use and hides the discrepancy. If the key genuinely changed, verify it and trust the new one instead.