GHOSTSHELL
Motion and effects on this site
Download 0.2.0

Security · GHOSTSHELL 0.2.0

Post-quantum where the protocol allows it. Labeled plaintext where it doesn't.

SSH offers four post-quantum hybrid key exchanges ahead of every classical one, led by ML-KEM-768 + X25519, and each tab shows the one the server chose. HTTPS, GhostVault's recovery and sharing, the release signatures and ML-DSA-44 + Ed25519 host keys pair a post-quantum algorithm with a classical one the same way. Where a protocol cannot, GHOSTSHELL says so: Telnet and raw sockets connect after a warning, VNC is marked unencrypted, and RDP hands over to Windows' own client.

Fig. 0 A real hybrid key exchange, run in your browser: on ML-KEM-768's ring of 3,329 values, the secret key strips the mask from the 256 coefficients of a 16 × 16 ghost, each winding down its own helix to the pole of its bit. The inner dial is X25519's 255-step ladder; K is SHA-256 of both secrets. Once the demo below runs, the ring follows it.The ring of 3,329 values ML-KEM-768 decrypts on: 0 at the top, 1,665 at the bottom, and the rounding horizon between them.

01 What protects what

Every connection and store, and what protects it in 0.2.0.

The kind of protection, stated plainly: post-quantum hybrid where GHOSTSHELL pairs ML-KEM, NTRU Prime or ML-DSA with a classical algorithm, symmetric where 256-bit keys do the work, classical where only classical keys or methods are in use, and none where the protocol has no encryption of its own.

What protects each connection and store in GHOSTSHELL 0.2.0
AreaIn 0.2.0Kind
SSH key exchangeFour post-quantum hybrids ahead of every classical method: ML-KEM-768 + X25519 first, then ML-KEM-1024 + P-384, ML-KEM-768 + P-256 and sntrup761 + X25519. The terminal and the tab show the one the server chose, with a warning when it is classical mlkem768x25519-sha256PQ hybrid
SSH ciphersAES-256-GCM first, then ChaCha20-Poly1305; SHA-1, CBC and 128/192-bit ciphers off by default aes256-gcm@openssh.com256-bit symmetric
SSH host and user keys, ML-DSAML-DSA-44 + Ed25519, asked for first from a server not yet trusted, and usable as your login key; its SSH format is still an IETF draft ssh-mldsa44-ed25519PQ hybrid
SSH host and user keys, classicalEd25519, ECDSA and RSA with SHA-2, the keys most servers have today; a server already trusted keeps its key type ssh-ed25519Classical
SSH through a proxy commandThe outside program's own connection is outside every policy, and Windows' ssh.exe (OpenSSH 9.5) has no post-quantum key exchange; a jump host keeps the policy on every hopOutside
HTTPS through NodeX25519MLKEM768 first, then ML-KEM-1024 alone, then the classical groups X25519MLKEM768PQ hybrid
GhostVault secretsPasswords, key passphrases and, if you choose, the whole config.yaml: Argon2id, HKDF-SHA-512, AES-256-GCM256-bit symmetric
GhostVault recovery, escrow, sharingML-KEM-1024 + P-384 to encrypt recovery and escrow slots and bundles, ML-DSA-87 + P-384 to sign bundles; ML-KEM-1024 and ML-DSA-87 are the parameter sets CNSA 2.0 namesPQ hybrid
GhostLine history, session logsAES-256-GCM per record, off by default256-bit symmetric
ReleasesFrom 0.2.0, the installer and the portable zip are signed with the release key, ML-DSA-44 + Ed25519, and this site checks the installer's signature in your browser. This version carries no release signature, so only its SHA-256 vouches for it.Hash only
RDPWindows' own Remote Desktop Connection, started with a generated .rdp file: the encryption is Windows' TLS, whose hybrid post-quantum groups are off by defaultWindows
VNCThe embedded viewer, RFB 3.3, 3.7 and 3.8: unencrypted, and labeled that wayNone
Telnet, raw socketsPlain text, passwords included; a warning before connectingNone
SerialA console cable on a COM port: no cryptography at allNone

PQ hybrid post-quantum and classical together 256-bit symmetric keys a quantum computer would at most halve in strength Classical elliptic-curve or RSA alone None no encryption in the protocol

02 Key exchange

Two locks. Either one holds.

GHOSTSHELL implements the four post-quantum key exchanges published for SSH as RFCs and offers them ahead of every classical method. Each is a hybrid: a post-quantum KEM, ML-KEM or Streamlined NTRU Prime, runs beside a classical elliptic-curve exchange, and both secrets are hashed into the session key. When the server supports one of them, a session recorded today stays sealed as long as either half holds, against a future quantum computer or a flaw in young post-quantum code. When it supports none, the connection is classical and the terminal and the tab say so, or, under Quantum-safe only, it is refused.

kex      mlkem768x25519-sha256
         mlkem1024nistp384-sha384
         mlkem768nistp256-sha256
         sntrup761x25519-sha512
         sntrup761x25519-sha512@openssh.com
         curve25519-sha256
         …
hostkey  ssh-mldsa44-ed25519
         ssh-mldsa44-ed25519@openssh.com
         ssh-mldsa-87
         ssh-mldsa-65
         ssh-mldsa-44
         ssh-ed25519
         …
cipher   aes256-gcm@openssh.com
         chacha20-poly1305@openssh.com
         …
Policies
Quantum-safe only · Quantum-safe preferred (default) · Compatible · Legacy
Quantum-safe only
The post-quantum methods and nothing else: a server without one is refused, with what it offers
Preferred
Every post-quantum hybrid first, even in a profile saved before that method existed, then the profile's classical methods without SHA-1
Compatible, Legacy
The profile's own ticked choices (Compatible) or everything the SSH library supports (Legacy), post-quantum first, for older equipment
Shown
After the handshake, before any password prompt, the terminal prints Post-quantum key exchange: mlkem768x25519-sha256 · host key ssh-ed25519, or a warning that the exchange is classical. The tab carries a badge, and Connection security… lists every hop
Terrapin
Strict key exchange against CVE-2023-48795, always offered
Never
The unencrypted none cipher or MAC, under any policy
Every hop
A jump host gets at least the policy of the connection through it, and tabs share a connection only under the same policy
Library
GHOSTSHELL's own build of russh 0.65.1, which fixes the October 2026 russh advisories, with RustCrypto's ml-kem and sntrup-kem
The post-quantum SSH key exchanges, in the order GHOSTSHELL offers them, and how each was tested
MethodWhat it isTested against
mlkem768x25519-sha256ML-KEM-768 with X25519, RFC 10042; OpenSSH's default since 10.0OpenSSH 10.5
mlkem1024nistp384-sha384ML-KEM-1024 with ECDH P-384, RFC 10042. OpenSSH 10.5 does not have it, so it was tested against the project's own server, a rekey and a jump host included, and its ML-KEM-1024 against OpenSSL 3.5 in both directionsOwn server
mlkem768nistp256-sha256ML-KEM-768 with ECDH P-256, RFC 10042, for servers limited to NIST curves; its ML-KEM-768 was also checked against OpenSSL 3.5OpenSSH 10.5
sntrup761x25519-sha512Streamlined NTRU Prime with X25519, RFC 9941; the RFC's shared-secret test vector and the published sntrup761 test vectors passOpenSSH 10.5
sntrup761x25519-sha512@openssh.comThe same method under the name OpenSSH 8.5 to 9.8 use. Under one name or the other, the method was OpenSSH's default from 9.0 until 10.0OpenSSH 10.5
mlkem1024-sha384ML-KEM-1024 alone, from the CNSA 2.0 SSH profile, a draft that defines the exchange hash two contradictory ways. Not built, so never offeredNot built

OpenSSH 10.5: the OpenSSH 10.5 client from Git for Windows completed a session with the method, a rekey included, against a test server built on GHOSTSHELL's SSH library, and both sides logged the method; a single differing byte would have changed the exchange hash and failed the connection. Own server: the app's SSH binding against that test server, which runs the same library. The binding completed every method built here against it. No OpenSSH server (sshd) has been tested from the app yet.

OpenSSH 10.5
60 of 60 checks: its client against the test server for every key exchange both have, with ML-DSA and classical host keys, an ML-DSA user key, rekeys, ciphers, MACs and compression, and SSHSIG signatures both ways
The app's binding
94 of 94 against the same server, inside Electron 43.7.0's runtime: every method and key type it implements, keyboard-interactive login, SFTP, port forwarding and a jump host
OpenSSL 3.5
28 of 28 for ML-DSA keys and signatures, both directions; ML-KEM-768 and ML-KEM-1024 in the SSH library's own tests, both directions
Unit tests
245 in the app: 244 pass, and the one skipped covers pure ML-KEM-1024, which is not built
Decrypt with
  1. The message is the 16 × 16 ghost: 256 bits, exactly what ML-KEM carries.
  2. Each bit becomes 0 or 1,665 on a ring of 3,329 values, plus noise from the key exchange.
  3. The right key keeps the noise small. Rounding to the nearer pole returns every bit.
  4. Someone else's key leaves only noise. (ML-KEM would then fail its re-encryption check and hand back an unrelated key.)
Encapsulating…
A real ML-KEM-768 encapsulation, run in your browser with @noble/post-quantum 0.7.1, the library GhostVault uses (for ML-KEM-1024); the app's SSH key exchange runs ML-KEM inside its SSH library, GHOSTSHELL's build of russh with RustCrypto's ml-kem. Here the message is the ghost instead of random bytes; the decryption is FIPS 203's K-PKE.Decrypt, written out to show each value before rounding. An illustration, not a security tool.

03 Host keys and authentication

Post-quantum signatures, where the server has them.

For a server it has not trusted before, GHOSTSHELL asks for the hybrid ML-DSA-44 + Ed25519 host key first, under both its names, then ML-DSA alone, then Ed25519, ECDSA and RSA with SHA-2. A server already in its known hosts keeps the key type it is trusted with, so it is not asked about again; when a known server presents a key of a new type, the prompt says which type it was trusted with. ML-DSA private keys sign you in like any other key file.

A host key only has to hold during the handshake, so a session recorded today does not depend on it. What ML-DSA keys add is protection against a quantum computer impersonating a server, or you, at connection time, which the classical keys nearly every server has today cannot give. Post-quantum SSH signatures are still IETF drafts, so their names and formats may change.

SSH host and user key types, in the order GHOSTSHELL asks for them, and how each was tested
Key typeWhat it isTested against
ssh-mldsa44-ed25519ML-DSA-44 and Ed25519, both signing (draft-ietf-sshm-composite-sigs-00), under the name OpenSSH 10.6 enables. Its construction is the one OpenSSH 10.5 checked under the next row's name; OpenSSH 10.6 itself was not available, so this name was tested against the project's own server and OpenSSL 3.5Own server
ssh-mldsa44-ed25519@openssh.comThe same signature under the name OpenSSH 10.4 and 10.5 use. OpenSSH 10.5 verified the test server's host key signatures with a key its own ssh-keygen made, pinned in known_hosts, and refused an unknown one; a user key from ssh-keygen signed in through OpenSSH and through the app's bindingOpenSSH 10.5
ssh-mldsa-87 ssh-mldsa-65 ssh-mldsa-44ML-DSA alone (draft-sfluhrer-ssh-mldsa-08), after the hybrids: post-quantum, with no classical half to fall back on. Tested against the project's own server and OpenSSL 3.5; no other SSH implementation was availableOwn server
ssh-mldsa87-p384ML-DSA-87 with ECDSA P-384, from the composite draft. Not built: the draft gives its ML-DSA-87 signature as 4,896 bytes where FIPS 204 has 4,627, and leaves the ECDSA hash unspecifiedNot built
ssh-ed25519 ecdsa-sha2-nistp* rsa-sha2-*The classical keys most servers have; ecdsa-sha2-nistp521 only against the project's own serverOpenSSH 10.5

Not tested yet: signing in to an OpenSSH server (sshd) with an ML-DSA key, ML-DSA certificates, and ML-DSA keys held in an SSH agent. Host certificates are checked as bare keys, not as certificates.

04 HTTPS

X25519MLKEM768 first, then ML-KEM-1024, then the classical groups.

HTTPS that GHOSTSHELL makes through Node, for plugin installs and plugins' own requests, offers every post-quantum group its TLS library accepts ahead of the classical ones. That library is Electron 43's BoringSSL. It accepts the hybrid X25519MLKEM768 and MLKEM1024, which is ML-KEM-1024 alone, but neither NIST-curve hybrid (SecP256r1MLKEM768, SecP384r1MLKEM1024), so those two are not offered. The pre-standard X25519Kyber768Draft00 is never offered.

The policy applies from the next connection, in every window and in the main process. An encrypted configuration can be read only once GhostVault is unlocked, and until then the policy last applied stands in. Settings → Security shows the groups and TLS version actually in force, not the stored setting.

Chromium's own network stack, which the app uses for plugin search and update checks, keeps Chromium's defaults: X25519MLKEM768 first, with no way to refuse the classical groups. The toolbox's TLS check shows a server's certificate chain and the key exchange it negotiated, so you can see which one a host picks.

Quantum-safe only
X25519MLKEM768:MLKEM1024 over TLS 1.3; without a post-quantum group, connections fail rather than fall back
Preferred (default)
X25519MLKEM768:MLKEM1024:X25519:P-256:P-384:P-521, TLS 1.2 or later
Legacy
As preferred, with TLS 1.0 and 1.1 for old internal servers
Compatible
BoringSSL's own defaults, classical only in Electron 43: X25519, P-256, P-384
Tested
Under Node and under Electron 43.7.0's runtime, over 127.0.0.1: each policy's ClientHello captured on the wire; preferred reached servers limited to each post-quantum group the library accepts, to X25519 and to TLS 1.2, and Quantum-safe only refused X25519-only and TLS 1.2 servers

05 GhostVault

Noise is the lock.

GhostVault seals SSH passwords, key passphrases and, if you choose, the whole config.yaml with Argon2id and AES-256-GCM, symmetric cryptography that a quantum computer would at most halve in strength. The slots that recovery kits and escrow vaults open, and shared bundles, are encrypted with a hybrid of ML-KEM-1024 and ECDH P-384, so opening one without its key takes breaking both, and shared bundles are signed with ML-DSA-87 and ECDSA P-384, a signature counting only if both halves verify.

GV2:Argon2id:AES-256-GCM:HKDF-SHA-512:ML-KEM-1024+P-384:ML-DSA-87+P-384

Secrets
Argon2id (RFC 9106: 64 MiB, 3 passes, 4 lanes; 256 MiB at the high setting) → HKDF-SHA-512 → AES-256-GCM. Without a vault, SSH passwords and key passphrases go to Windows Credential Manager
Recovery, escrow, sharing
ML-KEM-1024 + ECDH P-384, combined with HKDF-SHA-512 in GHOSTSHELL's own construction, which binds both ciphertexts and both public keys; no third party has analyzed it
Signatures
ML-DSA-87 + ECDSA P-384 on shared bundles. A valid signature shows that a bundle is intact, not who sent it; escrow files carry none
History, logs
GhostLine history and session logs: AES-256-GCM per record, off by default. A log ends with a sealed marker, so a cut is detected; history has none
Lock
Lock now, the timeout (1 minute by default), screen lock and sleep zero-fill the master key. The identity's secret keys and the history and logs keys are JavaScript strings, which cannot be wiped: they stay in memory until it is reused
New passphrase
Replaces the master key, so the old passphrase does not open the new file. The identity and keyring are kept, so an old copy of the file and the old passphrase still open history, logs, bundles and escrow slots made later
Library
@noble/post-quantum 0.7.1 for ML-KEM and ML-DSA, which passes the NIST test vectors, has not been independently audited and makes no constant-time claim; @noble/hashes 2.4.0 for Argon2id; BoringSSL for the classical halves
Tested
Unit tests for the primitives, the Argon2id limits, tamper detection, passphrase change, rotation, escrow, bundles and the record files; the flows in the running app were last run for 0.1.0
GHOSTSHELL settings, Security page: what protects what, the post-quantum protections and their status.
Fig. 1 Settings → Security: what protects what, and its current status.

06 Releases

One release key, with two halves.

From 0.2.0, every installer and portable zip is signed with GHOSTSHELL's release key, which pairs ML-DSA-44 (FIPS 204) with Ed25519 in OpenSSH's signature format. Both halves sign, and a signature counts only when both verify, so it cannot be forged while either algorithm holds. This site checks the installer's signature in your browser, against the key it was built with; the file is never uploaded.

Key type
ML-DSA-44 + Ed25519 · ssh-mldsa44-ed25519@openssh.com
Fingerprint
SHA256:wcsMR20+ZSY6dRrHBgco/FFH9pOnyjqRh8A5u2s+C0M
Principal
releases@ghostshell.app
Namespace
ghostshell-release: a signature this key made for anything else never counts as a release
Checked by
ssh-keygen 10.5 when a release is signed, this site's build, and your browser when you drop the installer on the Download page. ssh-keygen, OpenSSL 3.5 and @noble agree on every test signature, the rejected ones included
ssh-keygen
OpenSSH 10.4 and 10.5 check this key type. 10.6 renamed it and will not, so a new release key will follow once a 10.6 build can sign
Not covered
The installer is not Authenticode-signed, and the app's updater checks no signature

GHOSTSHELL 0.2.0 carries no release signature yet, so only its SHA-256 vouches for the file. The key, the signature and how to check them

07 Limits

What this does not protect.

  • Servers without post-quantum key exchangeA server that supports none of the four methods gets classical key exchange under every policy but Quantum-safe only, which refuses it. The terminal and the tab say so, because traffic recorded from that session could be decrypted later by a quantum computer.
  • SSH host and user keysWith the Ed25519, ECDSA and RSA keys most servers have, authentication is classical: a quantum computer could impersonate the server or you at connection time. ML-DSA keys on both ends close that, under IETF drafts. Host certificates are checked as bare keys.
  • What was testedOpenSSH 10.5 was tested as the client, against a server built on GHOSTSHELL's SSH library; the app has not yet been tested against an OpenSSH server (sshd). mlkem1024nistp384-sha384, the OpenSSH 10.6 name of the ML-DSA hybrid and ML-DSA alone were tested only against the project's own server and OpenSSL.
  • Proxy commands, WinSCPA proxy command is an outside program, and its own connection is outside the policy: Windows' ssh.exe (OpenSSH 9.5) has no post-quantum key exchange. A jump host (ProxyJump) keeps the policy on every hop. WinSCP and container tools make their own connections too.
  • RDPWindows' Remote Desktop client carries the session over Windows' TLS, whose hybrid post-quantum groups are off by default; GHOSTSHELL adds no layer of its own.
  • VNCUnencrypted, and labeled that way: the embedded viewer has no VeNCrypt or TLS.
  • Telnet, raw socketsPlain text, passwords included; GHOSTSHELL warns before it connects.
  • SerialConsole cables over COM ports: no cryptography at all.
  • The librariesThe post-quantum libraries GHOSTSHELL builds on for SSH and GhostVault have had no independent audit: RustCrypto's ml-kem, ml-dsa and sntrup-kem in the SSH library (sntrup-kem is a release candidate), and @noble/post-quantum in GhostVault, which passes the NIST test vectors and makes no constant-time claim. HTTPS uses Electron's BoringSSL.
  • GhostVault in memoryLocking zero-fills the master key, but the identity and keyring keys stay in memory as strings until it is reused, and malware running as you can read an unlocked vault or the passphrase as you type it. A new passphrase keeps the identity and keyring.
  • The installerGHOSTSHELL 0.2.0 is not code-signed (Authenticode), so SmartScreen warns. The app's updater checks no signature. The release signature on the Download page shows a file was signed with GHOSTSHELL's release key; the SHA-256 alone shows only that it matches what this site publishes.