Paramiko raises BadHostKeyException
when the SSH server’s host key does not match the entry in your ~/.ssh/known_hosts
. This is often due to legitimate key rotation or a potential man-in-the-middle (MITM) attack. Follow these steps to securely diagnose and fix mismatched host keys.
1. Understand Host Key Verification
SSH uses host keys to authenticate servers. On first connection, the server’s public key is stored in known_hosts
. Subsequent mismatches trigger BadHostKeyException
to prevent MITM attacks.
2. Catch and Inspect the Exception
import paramiko from paramiko import BadHostKeyException ssh = paramiko.SSHClient() ssh.load_system_host_keys() ssh.set_missing_host_key_policy(paramiko.RejectPolicy()) try: ssh.connect('example.com', username='user') except BadHostKeyException as e: print("Host key mismatch detected!") print("Expected:", e.expected_key.get_base64()) print("Received:", e.hostkey.get_base64()) raise
3. Verify Legitimate Key Rotation
- Obtain the new host key fingerprint from the server administrator via a secure channel (e.g., email, console, notarized file).
- Compare the fingerprint with
ssh-keyscan
output:ssh-keyscan example.com | ssh-keygen -lf -
Note: Never trust an unsolicited key change without verification.
4. Update known_hosts Safely
- Backup your known_hosts file:
cp ~/.ssh/known_hosts ~/.ssh/known_hosts.bak
- Remove the old entry:
ssh-keygen -R example.com
- Add the new key:
ssh-keyscan example.com >> ~/.ssh/known_hosts
5. Automate Key Replacement in Paramiko
For controlled environments, automate removal and addition:
import os import paramiko host = 'example.com' known_hosts = os.path.expanduser('~/.ssh/known_hosts') # Remove old key os.system(f'ssh-keygen -R {host}') # Append new key os.system(f'ssh-keyscan {host} >> {known_hosts}') # Proceed with connection ssh = paramiko.SSHClient() ssh.load_system_host_keys() ssh.connect(host, username='user')
Tip: Restrict automation to trusted infrastructure to avoid MITM risk.
6. Use Custom HostKeyPolicy for Warnings
Display warning instead of rejecting:
from paramiko import SSHClient, WarningPolicy ssh = SSHClient() ssh.load_system_host_keys() ssh.set_missing_host_key_policy(WarningPolicy()) ssh.connect('example.com', username='user') # WarningPolicy prints a warning and adds the key to host keys
7. Summary Checklist
- Catch
BadHostKeyException
and inspect expected vs. received fingerprints. - Verify new host key via secure channel or
ssh-keyscan
. - Backup and update
known_hosts
usingssh-keygen -R
andssh-keyscan
. - Automate update carefully in trusted environments.
- Optionally use
WarningPolicy
for non-blocking warnings in development.