Skip to content

Security: casablanque-code/khm

Security

SECURITY.md

Security Policy

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.

Supported Versions

Only the latest release receives security fixes.

Version Supported
0.3.x
< 0.3

Reporting a Vulnerability

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)

Scope

Things we care about most:

  • Memory-safety bugs in the SSH wire-format parsers (hostkey.c) or the known_hosts line 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 a known_hosts file)
  • Anything that makes verify/doctor report 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-crafted known_hosts (oversized, or with adversarial content) cause excessive memory/CPU use — see the Security Notes below for what's already in place against these

Out of Scope

  • 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_hosts file or local disk (khm trusts local files it's pointed at, same as ssh itself does)

Security Notes

  • 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 HashKnownHosts entries in khm 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 why tests/fuzz/ targets exactly this code
  • khm normalize --write backs up the original file to <path>.khm-backup before an atomic replace, by default (--no-backup to skip). If the backup itself can't be written, the command aborts rather than proceeding without one
  • @cert-authority/@revoked marker lines are parsed and preserved verbatim by every command that rewrites a known_hosts file — this wasn't always true (see CHANGELOG.md 0.3.0) and is called out here because a silently-dropped @revoked line is exactly the kind of bug this policy exists to catch early. doctor flags @cert-authority lines as present but never verifies certificates signed by them — khm has no certificate/CA chain validation at all
  • normalize --write's temp file is opened with O_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 final rename() step itself — POSIX rename() never dereferences a symlink at the destination, it replaces the link, so known_hosts being a symlink was already safe against that specific attack)
  • doctor checks known_hosts's own permission bits — warns if group/world-writable, notes if world-readable or a symlink
  • known_hosts files 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 input
  • khm scan requires --force for a CIDR range reaching outside private address space (RFC 1918 / loopback / link-local / RFC 6598 CGNAT) — not a vulnerability in khm itself, but scanning 0.0.0.0/0 by a typo'd prefix shouldn't be one keystroke away
  • Past fixes in this area are documented in CHANGELOG.md under each release's ### Security section (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

There aren't any published security advisories