My SSH private key got exposed. What should I do?
An SSH private key is a master credential. Anyone who holds it can authenticate as you to every server where the corresponding public key is listed in authorized_keys — silently, with no password required. Revocation is the only safe response, and it needs to happen in the next few minutes.
Act immediately — SSH keys don't expire on their own.
Unlike passwords that can be changed server-side, the exposed private key remains valid until you explicitly remove its public key from every authorized_keys file on every server it's authorised on. Until you do that, the door is open.
// the 60-second version
- Remove the exposed public key from every
authorized_keysfile on every server. - Generate a new key pair and deploy the new public key before revoking the old one if it's your only access.
- Audit SSH auth logs for logins using the compromised key during the exposure window.
- Never store private keys in a web-accessible directory or commit them to a repository.
01Understand what an exposed private key means
SSH uses asymmetric cryptography: you hold a private key, and a copy of the corresponding public key is placed in ~/.ssh/authorized_keys on each server you access. When you connect, the server challenges you to prove you hold the private key — no password needed.
If an attacker has your private key, they can:
- Log in to any server where the public key is authorised — including production, staging, and any other environment.
- Access any service that uses SSH-based authentication — GitHub, GitLab, Bitbucket deploy keys, and similar.
- Pivot to other systems from the compromised server — internal networks, databases, cloud metadata endpoints.
- Plant persistence — add their own public key to
authorized_keysso they retain access even after you rotate yours.
If the key was unencrypted (no passphrase), it can be used immediately with no additional steps. Even a passphrase-protected key is at risk if the passphrase is weak — assume the worst.
02Immediately revoke from all authorized_keys
You need to find and remove the exposed public key from every server it's authorised on. First, derive the public key fingerprint from the private key so you can identify it precisely:
# derive the public key from the private key ssh-keygen -y -f id_rsa_exposed # get its fingerprint ssh-keygen -lf id_rsa_exposed
Then, on each server, remove every line containing that public key from the authorized_keys file:
# view current authorized keys cat ~/.ssh/authorized_keys # remove the specific key by its comment or fingerprint # make a backup first cp ~/.ssh/authorized_keys ~/.ssh/authorized_keys.bak # delete lines matching the exposed key's comment grep -v "your_username@hostname" ~/.ssh/authorized_keys \ > ~/.ssh/authorized_keys.new mv ~/.ssh/authorized_keys.new ~/.ssh/authorized_keys
Also revoke any deploy keys on GitHub, GitLab, or Bitbucket that used this key pair. Go to each repository's Settings > Deploy Keys and delete the exposed entry.
03Generate a new key pair
Before revoking the old key (if it's your only way in), generate a new one and deploy the public key to all servers. Use Ed25519 — it's modern, fast, and produces shorter keys than RSA:
# generate a new key with a strong passphrase ssh-keygen -t ed25519 -C "your@email.com" -f ~/.ssh/id_ed25519_new # copy the new public key to each server ssh-copy-id -i ~/.ssh/id_ed25519_new.pub user@server1 ssh-copy-id -i ~/.ssh/id_ed25519_new.pub user@server2 # test the new key works before revoking the old one ssh -i ~/.ssh/id_ed25519_new user@server1 "echo connected"
Only after confirming the new key grants access should you remove the old key from authorized_keys.
04Audit SSH logs for unauthorised access
Determine the exposure window — when was the private key first potentially accessible, and when did you revoke it? Then check whether the key was used during that window:
# on Debian/Ubuntu grep "Accepted publickey" /var/log/auth.log | grep -v "your_own_ip" # on RHEL/CentOS grep "Accepted publickey" /var/log/secure # check for new entries in authorized_keys (attacker persistence) cat ~/.ssh/authorized_keys
Look for logins from IP addresses you don't recognise, at times outside normal working hours, or with activity (commands, file transfers) that you didn't perform. If you find evidence of unauthorised access, treat the server as potentially compromised and conduct a more thorough incident response.
05Prevent SSH private keys from being exposed
- Never store private keys in a web-accessible directory. SSH keys belong in
~/.ssh/with permissions600— never in/var/www/or any publicly served path. - Never commit private keys to a git repository. Add
id_rsa,id_ed25519, and*.pemto.gitignore. Use pre-commit hooks or tools like git-secrets to catch them before they're committed. - Always use a strong passphrase. A passphrase adds a layer of protection if the key file is stolen — the attacker still needs to crack the passphrase.
- Use an SSH agent so the decrypted key lives only in memory, not on disk in the web root.
- Scope deploy keys. Use separate, read-only deploy keys per repository rather than your personal key — a compromised deploy key limits the blast radius.
If the compromised server stores personal data and there is evidence of unauthorised access, this may constitute a data breach requiring notification under GDPR or equivalent regulations. Document the exposure timeline and consult your legal team.
Was this guide useful?
These playbooks are free to read and share. If a heads-up ever saved you a bad week, you can say thanks — or jump into the other guides.