whiteweb.security / guides / SSH key exposed
id_rsa / id_ed25519 Critical exposure ~7 min read

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_keys file 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_keys so 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:

get the fingerprint of the exposed keybash
# 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:

remove the key from authorized_keysbash (on each server)
# 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 Ed25519 key pairbash
# 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:

check auth logs for SSH loginsbash (on each server)
# 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 permissions 600 — never in /var/www/ or any publicly served path.
  • Never commit private keys to a git repository. Add id_rsa, id_ed25519, and *.pem to .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.