SECURITY
Your keys are encrypted on your device before anything leaves it, so our server only ever holds data it cannot read. The demos below run the real cryptography in your browser, and nothing you type into them ever leaves your browser: flip a byte and watch it get rejected, put an attacker on the wire and watch the host key catch them. Encryption and sync are free on any storage you run, Juiced only buys the hosting.
Reflects ZestSSH v2.3.0 · Last reviewed September 2026
How a password becomes a key, how that key is stored so we never see it, and how the data itself is sealed.
What sits on your disk, and what someone holding the file actually gets.
Proving the server is really the server, before a keystroke is sent.
Your password is not the key. It is too short and too guessable to be one. ZestSSH runs it through Argon2id, a deliberately slow, memory-hungry function that eats 128 MB of RAM per attempt and mixes in a random salt. Out comes a full 256-bit key. The slowness is the whole point: it costs you a fraction of a second once, and it costs an attacker a fortune per guess.
A slow, salted, one-way function. Even a huge GPU farm is throttled to a trickle of guesses per second because each one needs 128 MB it cannot share.
A weak, common password. No key derivation saves password123. Length and unpredictability are the one part only you control.
How does ZestSSH know your password is right, if it never keeps your password or your key? It stores a small verification value, derived from the key through HKDF-SHA256. On unlock it derives the value again and compares. Right password, values match. Wrong password, they do not. The value is one-way: it cannot be turned back into your key or your password.
Steal the device file and you get a one-way fingerprint, not the password or key. The comparison is constant-time, so it leaks nothing through timing either.
Nothing here alone, this is a check, not the lock. Its strength rides entirely on your password: a weak password makes both the key and this value guessable.
Here is the trick that makes ZestSSH both recoverable and zero-knowledge. Your data is locked by one random Data Key. That Data Key is never exposed, it is sealed inside two independent envelopes: one you open with your password, one you open with your recovery key. Either opens the same Data Key. Neither envelope reveals the other.
Two independent ways in, so a forgotten password is not a lost account. And the server only ever stores sealed envelopes, it never sees the Data Key or your password.
Losing both at once. That is not a bug, it is zero-knowledge: if neither you nor anyone else can open an envelope, the data is math, not recoverable. Keep the recovery key somewhere real.
This is the one demo on the page that shows a ZestSSH design choice rather than a textbook fact about a cipher. Because the Data Key is wrapped, not derived from your password, changing your password only re-seals one small envelope. The Data Key never changes, so your entire encrypted database stays exactly where it is, byte for byte. That is why a password change is instant instead of a full re-encryption.
Instant password changes, and a recovery key that is a fully independent second envelope, not a copy of your password. Rotating one never touches your data or the other path.
The envelopes are only as strong as what seals them, which loops straight back to gate 01: a weak password is a weak envelope, no matter how elegant the indirection.
Now the Data Key does its job with AES-256-GCM. GCM does two things at once: it scrambles the data, and it stamps a 16-byte authentication tag over every single byte. If anything changes later, even one bit, the tag no longer matches and decryption refuses to run. It never hands back half-right or attacker-tweaked data. This demo runs the real cipher, right here.
Confidentiality and integrity together. A tampered backup, a corrupted sync, a byte flipped by an attacker: all rejected outright, not silently trusted.
Reusing a nonce with the same key would leak patterns. ZestSSH draws a fresh random nonce for every message, so it never happens.
Everything on your device lives in a SQLCipher database, encrypted as a whole. The database key is itself wrapped behind your PIN, and you can bind that wrapping to the device's hardware security chip: Keystore or Secure Enclave on mobile, the TPM on Windows. Steal the file and you get noise. Steal the file off a hardware-bound device and it is noise that will not open anywhere else.
A lost or stolen, locked device is a brick full of ciphertext. Hardware binding means even a byte-for-byte copy of the file is useless on the attacker's machine.
An already-unlocked device in someone's hands: the key is live in memory. That is exactly why auto-lock exists and defaults to a short timeout.
When you connect, three things happen before a single keystroke is sent. Both sides agree on a shared key without ever transmitting it (X25519). The server proves it is really itself by signing with its host key (Ed25519), and you check that signature against the fingerprint you trust. Then the whole channel is sealed with authenticated encryption. Run it, then let a man in the middle try to sit in between.
Someone recording the whole exchange still cannot derive the session key. And an impostor server cannot fake the host key's signature, so ZestSSH catches it and warns you loudly.
Clicking through a host-key-changed warning. That warning is the interception alarm. On a real network it is the one thing you must never wave past.
This is the part worth remembering. Pick an attack and see which locks stop it cold and which ones it walks straight past. Honest security is knowing where the wall is, and where the door you have to guard is.
Everything above you can watch happen. These you have to be told, so they are short. Anything deeper lives in the whitepaper, which is what a reviewer reads anyway.
Zero analytics, zero crash reporting, zero telemetry. No Firebase Analytics, no Crashlytics, no usage tracking of any kind. We have no idea how you use the app, how often you open it, or what servers you connect to.
What does leave your device is limited, disclosed, and only when you use the feature that needs it: purchase verification, Firebase sign-in if you enable sync, an optional avatar upload, any automation webhook or monitoring endpoint you configure, an anonymous update check on desktop, a service status check while the Help panel is open, and a bug report or suggestion only when you send one yourself from the Help panel (what you typed, the app version and platform, and an optional screenshot that is redacted by default; it is posted to the public ZestSSH Discord, and if you are signed in your account id rides along for rate limiting only, never shown there; no install identity). None of it carries your vault data. Full egress inventory in the whitepaper and the Privacy Policy.
Sync setup issues a one-time recovery key, generated on your device, shown once, never sent to us, formatted ZEST-XXXX-XXXX-XXXX-XXXX-XXXX. It opens your vault if you forget your password. If you lose both your password and your recovery key, your data is permanently unrecoverable, that is the tradeoff of real end-to-end encryption: a server that cannot read your data also cannot help you recover it.
Local backups (.zest files) use the same primitives: AES-256-GCM with an Argon2id key from a password you choose. Because they are encrypted with your password and not a key we hold, you can safely store them in any cloud drive.
What is synced: SSH connections (including each host's last-used remote SFTP folder, which you can clear per host), identities, private keys, stored passwords, known_hosts, groups, snippets, and port-forwarding rules, serialized, compressed, and AES-256-GCM encrypted before anything leaves the device.
The desktop SFTP browser can point each pane at a different host, so you can copy straight from one server to another. That copy passes through your own device, never our infrastructure: ZestSSH downloads the file to a temporary file on your disk, uploads it to the destination, and deletes it when the copy finishes. A move within a single server is a server-side rename, so those bytes never leave that server at all.
When a shell turns on bracketed paste, ZestSSH sends a multi-line paste as one block the shell will not auto-run, so a stray trailing newline cannot fire a half-pasted command. A raw shell, many full-screen prompts and device consoles leave that mode off, and there Dangerous Command Protection is the backstop: it holds a paste, a snippet run, or a broadcast that carries a flagged command (rm -rf, mkfs, dd, a fork bomb, curl piped to a shell, shutdown) and asks first. Commands you type by hand are never intercepted.
The Automation Engine is default OFF and must be enabled with a warning shown first. External apps authenticate with per-key API keys stored in OS-native secure storage (never plaintext), compared in constant time, and rate-limited.
What it cannot do: run arbitrary commands you did not pre-configure, read or exfiltrate your SSH keys and passwords, bypass host-key verification, or run at all while the engine is off. Full model in the whitepaper.
Every public release is compiled with Dart obfuscation, symbols split out and kept private. Destructive account operations (deleting sync data or the account) require proof you hold your sync password, not just a valid login token, so a stolen session cannot wipe your data.
ZestSSH is built by one person, and I take security reports seriously. Email [email protected]. I can't offer cash, but validated findings get a free Squeezed license or Juiced upgrade, public acknowledgment if you want it, and my genuine thanks. See the full disclosure policy.
Encryption and sync are free on storage you run. Juiced buys the hosting, not the privacy.