Introduction

OpenSSH uses HashKnownHosts yes by default in many distributions, which stores hostnames and IP addresses as HMAC-SHA1 hashes in the known_hosts file. This prevents an attacker who gains read access to the file from discovering which servers you connect to. However, hashing makes it impossible to manually audit which hosts are tracked, complicates host key rotation, and makes it difficult to verify compliance with key pinning policies.

Symptoms

  • cat ~/.ssh/known_hosts shows entries like |1|randomhash|randomhash ssh-ed25519 AAAA...
  • Cannot determine which servers are in your known_hosts file
  • Cannot grep for a specific hostname to check its key
  • Automated scripts that parse known_hosts fail on hashed entries
  • Compliance audit requires a plaintext inventory of connected hosts and their keys

Common Causes

  • HashKnownHosts yes set in system-wide ssh_config (/etc/ssh/ssh_config)
  • SSH client compiled with hashing enabled by default
  • User manually hashed existing entries with ssh-keygen -H
  • Configuration management tool enforcing hashed known_hosts
  • Security policy requiring host identity protection

Step-by-Step Fix

  1. 1.Check if hashing is enabled:
  2. 2.```bash
  3. 3.grep -i HashKnownHosts /etc/ssh/ssh_config ~/.ssh/config 2>/dev/null
  4. 4.# Check the file for hashed entries
  5. 5.head -5 ~/.ssh/known_hosts
  6. 6.# Hashed entries start with |1|
  7. 7.`
  8. 8.Check if a specific host is in known_hosts (hashed):
  9. 9.```bash
  10. 10.# ssh-keygen can check hashed entries
  11. 11.ssh-keygen -F server.example.com
  12. 12.# Returns the matching hashed entry if found
  13. 13.`
  14. 14.Unhash known_hosts entries for auditing:
  15. 15.```bash
  16. 16.# Create a backup first
  17. 17.cp ~/.ssh/known_hosts ~/.ssh/known_hosts.backup
  18. 18.# Disable hashing
  19. 19.sed -i 's/HashKnownHosts yes/HashKnownHosts no/' ~/.ssh/config
  20. 20.# Recreate known_hosts by connecting to each host again
  21. 21.# Or manually unhash if you know the hostnames
  22. 22.`
  23. 23.Hash an existing plaintext known_hosts:
  24. 24.```bash
  25. 25.ssh-keygen -H -f ~/.ssh/known_hosts
  26. 26.# This hashes all plaintext entries in-place
  27. 27.rm ~/.ssh/known_hosts.old # The backup created by -H
  28. 28.`
  29. 29.Export a human-readable inventory for compliance:
  30. 30.```bash
  31. 31.# For each entry, get the hostname and fingerprint
  32. 32.while IFS= read -r line; do
  33. 33.if [[ "$line" == "|1|"* ]]; then
  34. 34.echo "HASHED: $line"
  35. 35.else
  36. 36.host=$(echo "$line" | awk '{print $1}')
  37. 37.fingerprint=$(echo "$line" | ssh-keygen -lf /dev/stdin 2>/dev/null)
  38. 38.echo "$host -> $fingerprint"
  39. 39.fi
  40. 40.done < ~/.ssh/known_hosts
  41. 41.`
  42. 42.Disable hashing for specific hosts only:
  43. 43.```bash
  44. 44.# In ~/.ssh/config:
  45. 45.Host audited-servers
  46. 46.HostName server1.example.com server2.example.com
  47. 47.HashKnownHosts no

Host * HashKnownHosts yes ```

Prevention

  • Balance security (hashing) with operability (plaintext) based on your environment
  • For compliance-heavy environments, use SSH certificates with a CA instead of known_hosts
  • Maintain a separate plaintext inventory of all server host keys for auditing
  • Use configuration management to deploy known_hosts entries in a controlled manner
  • Document the hashing policy and provide procedures for key verification during audits