khm implements a partial SSH handshake by hand (banner exchange, KEXINIT,
KEX_ECDH_INIT/_REPLY) to fetch a live host key, with no libssh or
OpenSSL involved. That's the whole point of the tool, and also exactly
where a parsing bug would hurt most — the wire-format parsers are the one
place khm processes bytes it didn't generate itself, sent by whatever's on
the other end of verify/scan/doctor --check-reachable.
Only the latest release receives security fixes.
| Version | Supported |
|---|---|
| 0.3.x | ✅ |
| < 0.3 | ❌ |
Please do not open a public GitHub issue for security vulnerabilities.
Email: casablanque@proton.me Response time: within 72 hours
Include in your report:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
Things we care about most:
- Memory-safety bugs in the SSH wire-format parsers (
hostkey.c) or theknown_hostsline parser (parser.c) — these are the only two places khm parses input it didn't produce itself (a live server's handshake bytes, and the contents of aknown_hostsfile) - Anything that makes
verify/doctorreport a host as trusted (OK) when it shouldn't be, or silently skip a check it claims to run - Data loss or silent corruption in
normalize --write— it rewrites a trust database in place, atomically, and is explicitly the most dangerous command in this tool by design; a bug here is worse than a bug anywhere else - Anything letting a malicious/compromised SSH server crash khm or corrupt
memory during a fetch (
verify,fingerprint,scan,doctor --check-reachable) - Symlink/TOCTOU issues around
normalize --write's temp-file handling, or anything that lets a maliciously-craftedknown_hosts(oversized, or with adversarial content) cause excessive memory/CPU use — see the Security Notes below for what's already in place against these
- Vulnerabilities in the target SSH server itself, or in OpenSSH — khm only ever performs a partial, unauthenticated handshake to read a host key; it never authenticates, opens a session, or executes anything
- Issues that require the user to already control their own
known_hostsfile or local disk (khm trusts local files it's pointed at, same assshitself does)
- khm never authenticates to a remote host, opens a shell, or transmits credentials of any kind — every network operation is read-only: connect, exchange banners, negotiate KEX, read the host key, disconnect
- No third-party crypto library is linked in — SHA-256, SHA-1/HMAC-SHA1
(used only for recovering
HashKnownHostsentries inkhm lookup), and the ECDH handshake bytes are all self-contained implementations in this repo. That's a deliberate trade-off (see README) — it also means khm carries the burden of getting these right itself, which is why the wire parsers are the top scope item above and whytests/fuzz/targets exactly this code khm normalize --writebacks up the original file to<path>.khm-backupbefore an atomic replace, by default (--no-backupto skip). If the backup itself can't be written, the command aborts rather than proceeding without one@cert-authority/@revokedmarker lines are parsed and preserved verbatim by every command that rewrites aknown_hostsfile — this wasn't always true (see CHANGELOG.md 0.3.0) and is called out here because a silently-dropped@revokedline is exactly the kind of bug this policy exists to catch early.doctorflags@cert-authoritylines as present but never verifies certificates signed by them — khm has no certificate/CA chain validation at allnormalize --write's temp file is opened withO_CREAT|O_EXCL|O_NOFOLLOW, refusing to write through a pre-existing file or symlink at that exact path rather than following it (closes a TOCTOU window, not a bug in the finalrename()step itself — POSIXrename()never dereferences a symlink at the destination, it replaces the link, soknown_hostsbeing a symlink was already safe against that specific attack)doctorchecksknown_hosts's own permission bits — warns if group/world-writable, notes if world-readable or a symlinkknown_hostsfiles over 100 MiB, or with more than 200,000 lines, are refused before parsing (parser.c,KHM_MAX_FILE_SIZE/KHM_MAX_LINES) — well above any real file, purely to bound memory use against a hostile or corrupted inputkhm scanrequires--forcefor a CIDR range reaching outside private address space (RFC 1918 / loopback / link-local / RFC 6598 CGNAT) — not a vulnerability in khm itself, but scanning0.0.0.0/0by a typo'd prefix shouldn't be one keystroke away- Past fixes in this area are documented in
CHANGELOG.md under each release's
### Securitysection (0.2.1: non-random ECDH ephemeral key; 0.2.2: integer underflow in packet-length parsing; 0.2.3: base64 write buffer overflow) — kept there rather than duplicated here so there's one place with the full, dated history