SevyDevy

Guide · Backend

GitHub's November 2026 SSH RSA Brownout Explained: Fix Clients, Keep RSA Keys

22 min readUpdated By Saket Bhatnagar

Researched and drafted with AI, reviewed and edited by Saket Bhatnagar.

In short

  • The GitHub SSH RSA deprecation removes two old options for Git over SSH (Secure Shell) on 13 January 2027. One is ssh-rsa: signing logins with an RSA key, one type of SSH key, after shrinking the data with SHA-1, a hash function GitHub calls weak. The other is diffie-hellman-group-exchange-sha256, an old key exchange, the step where both sides agree a secret session key.
  • Brownouts, planned temporary switch-offs that make old clients fail early, come first on 4 November and 9 December 2026. As of 19 October 2026, GitHub has not published their hours.
  • Your RSA key is not banned. It keeps working when your SSH software signs with rsa-sha2-256 or rsa-sha2-512, the SHA-2 recipes. GitHub lists OpenSSH 7.2p1 as the minimum OpenSSH that does this by default.
  • From 14 October 2026, GitHub requires new RSA keys you upload to be at least 3072 bits. GitHub also scheduled mlkem768x25519-sha256 for that day: a key exchange built to resist future quantum computers.
  • Beginners can stop after the section on moving to Ed25519. Engineers then get a tested local rehearsal of both failures and the 2021 cutoff that limits which RSA keys can break. They also learn why ssh -Q sig listing ssh-rsa is harmless.

What goes wrong when GitHub stops accepting old SSH signatures?

Builds and deploys that fetch code over SSH start failing, even though nobody changed a key or a line of code. SSH (Secure Shell) is the encrypted connection Git can use to talk to GitHub. That is the risk behind the GitHub SSH RSA deprecation for anyone with old build servers or SSH libraries.

Up-to-date laptops usually pass. GitHub says most SSH implementations that support RSA with SHA-2 choose it automatically. The trouble hides in machines and libraries nobody has touched for years.

Picture a common setup. A bill-payments team in Pune deploys about 25 times a day from a build server that pulls code from GitHub over SSH. The setup is made up, but the problem is real.

The team's SSH clients are a mixed bag. There are developer laptops, the build server with an old Java SSH library, a Windows box running PuTTY and a release bot written in Go. The build server logs in with a deploy key, an SSH key that can reach one repository. That RSA key was added in 2020.

A lost deploy day costs the team about 2.5 lakh rupees (250,000) in staff time and refunds. On 15 October, its deploy-key script fails, because it still makes 2048-bit RSA keys. The team now wants to know what else will break before 4 November.

What is the GitHub SSH RSA deprecation in 2026?

It is a set of four SSH changes GitHub announced on 22 September 2026: two removals, one stricter rule and one addition.

  • Removed: the ssh-rsa signature, which signs with an RSA key using SHA-1. GitHub says SHA-1 is known to be weak. RSA SSH certificates used with SHA-1 go too.
  • Removed: the diffie-hellman-group-exchange-sha256 key exchange. GitHub calls it slow and little used, and says advances in quantum computing could break it.
  • Stricter: RSA keys uploaded after 14 October 2026 must be at least 3072 bits. This covers both login keys and keys used to sign commits and tags.
  • Added: mlkem768x25519-sha256, a post-quantum key exchange, on github.com and GitHub Enterprise Cloud with data residency, except the US region.

An SSH certificate is a key signed by an organisation's own certificate authority, so it can be trusted without uploading each key. Only the SHA-1 kind, named [email protected], is removed.

Only SSH users are affected, plus anyone using the unauthenticated Git protocol on GitHub Enterprise Server. GitHub says that if your Git remotes start with https, nothing here affects you. The one exception is the 3072-bit rule, which also covers RSA keys you upload to sign commits. Run git remote -v to check: a remote starting [email protected] or ssh:// uses SSH.

What is the difference between an SSH key type and a signature algorithm?

A key type is the kind of key pair you own, such as RSA or Ed25519. A signature algorithm is the exact recipe used to sign with that key, including which hash function runs first.

At login, your SSH client signs data tied to this session with your private key. GitHub checks the signature with the public key you uploaded. A hash function first shrinks that data to a short, fixed-size fingerprint.

An RSA key can sign in more than one way. The old ssh-rsa recipe hashes with SHA-1. The rsa-sha2-256 and rsa-sha2-512 recipes, defined in RFC 8332 in March 2018, use SHA-256 or SHA-512.

Think of a bank updating its KYC (know your customer) form. Your Aadhaar number stays the same, and only the old form is refused. GitHub is retiring the old recipe, not your RSA key.

Where the picture breaks: you fill a form once, but your SSH software picks the recipe again at every login. That is why upgrading the software fixes the problem without touching the key.

Where the key exchange and the signature happen

Notice that the key exchange and the login signature are separate steps. This change retires one old recipe in each, so a client can fail at either point.

Diagram connections:

  • Developer laptop to Key exchange
  • Key exchange to Host key check
  • Host key check to Login signature
  • Login signature to Key and recipe allowed?
  • Key and recipe allowed? to Git fetch runs (Yes)
  • Key and recipe allowed? to Permission denied (No: ssh-rsa after removal)
  • Key exchange to Unable to negotiate (No: only DH-GEX after removal)
  • Developer laptop: Client → GitHub: opens an SSH connection
  • Key exchange: Client → GitHub: agree a secret session key
  • Host key check: GitHub → Client: signs the exchange to prove it is GitHub
  • Login signature: Client → GitHub: signs with rsa-sha2-512
  • Key and recipe allowed?: GitHub → GitHub: known key and allowed recipe?
  • Git fetch runs: GitHub → Client: code flows inside the tunnel
  • Permission denied: GitHub → Client: login refused
  • Unable to negotiate: GitHub → Client: no shared key exchange
Key types, signature recipes and key exchanges in GitHub's change, as of 19 October 2026
NameWhat it isStatus at GitHub
RSAKey typeAccepted; new uploads need 3072 bits
ssh-rsaSignature using SHA-1Removed 13 Jan 2027
rsa-sha2-256, rsa-sha2-512Signature using SHA-2Accepted
Ed25519Key typeAccepted; recommended for new keys
ECDSAElliptic-curve key type, older than Ed25519Accepted
DSA (ssh-dss)Key typeNot supported since 15 Mar 2022
diffie-hellman-group-exchange-sha256Key exchangeRemoved 13 Jan 2027
mlkem768x25519-sha256Post-quantum key exchangeScheduled from 14 Oct 2026

Why do existing RSA keys still work with the rsa-sha2-256 and rsa-sha2-512 signatures?

Because the hash is chosen each time you sign, not when the key is made. GitHub's changelog says all RSA keys are capable of signing with all hash algorithms, so you do not need a new key.

What matters is the software doing the signing. A very old client or library may only know ssh-rsa, so the same key fails from that machine.

In the team's setup, a developer's RSA key on a laptop and the build server's RSA deploy key both date from 2020. The laptop's OpenSSH signs with rsa-sha2-512 and keeps working. The build server's old Java library signs with ssh-rsa, so it will fail.

Here is the reassuring part. GitHub already refuses SHA-1 signatures from RSA keys added after 2 November 2021. So if such a newer key works for you today, the ssh-rsa removal will not break it.

Which SSH client versions still work after GitHub removes ssh-rsa?

GitHub's changelog lists six SSH clients and libraries, each with the minimum version that supports RSA with SHA-2 "robustly" (GitHub's word) in its default configuration. Anything older needs an upgrade or a different key type.

Minimum versions from GitHub's 22 September 2026 changelog
SoftwareMinimum versionWhere you may meet it
OpenSSH7.2p1The ssh command on Linux and macOS
JSch, mwiede fork0.1.66Java tools
TeamCity2021.2.3A continuous integration (CI) server
Go SSH0.16.0Go programs and bots
libssh21.11.0A C library inside other tools
PuTTY0.82A popular SSH client for Windows

A fork is a separately maintained copy of a project. Many Java tools bundle JSch, so check which copy and which version yours ships. GitHub adds that a client supporting RSA with SHA-2 should also support a strong key exchange.

The team checks each machine. The build server bundles an old JSch, the Windows box has PuTTY 0.76, and the bot pins an older Go SSH package. Only the laptops pass.

How do you test your SSH client against github.com?

Run ssh -T [email protected] for a quick login test, then ssh -vT [email protected] to see what was agreed. The -v flag turns on debug output, and each extra v adds detail, up to three.

  1. Run the basic test

    Run ssh -T [email protected]. GitHub's docs say a working login greets you by username and exits with code 1. OpenSSH exits with 255 when the connection or login fails.

  2. Add one v for the negotiation

    Run ssh -vT [email protected]. The kex: algorithm line names the key exchange that was agreed. The Offering public key line names your key type, such as RSA.

  3. Do not misread SHA256 in that line

    The SHA256: text after your key type is the key's fingerprint, not the signing recipe. Running ssh-keygen -l -f on your .pub file prints the same value.

  4. Add three v's for the signature

    Run ssh -vvvT [email protected]. In OpenSSH 9.6p1, 9.9p1 and 10.2p1, the signing using line appeared only at this level. It should name rsa-sha2-512 or rsa-sha2-256; if it says ssh-rsa, fix that machine.

bash
ssh -vvvT [email protected] 2>&1 | grep -E 'kex: algorithm|Offering public key|signing using'

# What OpenSSH 9.6p1 printed on our local test server (path and fingerprints shortened, trailing words cut):
# debug1: kex: algorithm: [email protected]
# debug1: Offering public key: ~/.ssh/id_rsa RSA SHA256:8CfLxasU...
# debug3: sign_and_send_pubkey: signing using rsa-sha2-512 SHA256:8CfLxasU...

SSH writes debug lines to standard error, the separate output stream programs use for messages, which is why the command adds 2>&1 before grep. The key exchange you see will vary with your client version. If it names diffie-hellman-group-exchange-sha256, check that machine's full list with ssh -G github.com | grep '^kexalgorithms '. If that method is the only one, the machine will fail; if curve25519-sha256 or newer is also listed, OpenSSH falls back to it.

What happens during GitHub's November and December 2026 SSH brownouts?

A brownout is a planned, temporary trial of the removal. GitHub switches off the ssh-rsa signature and the old key exchange for a while, so clients that need them fail early.

GitHub used the same pattern in its 2021 SSH clean-up, which dropped DSA keys, some old ciphers and SHA-1 signatures for newer RSA keys. Its 2021 announcement scheduled several short brownouts on 2 November 2021 and a final one on 11 January 2022, again without hours.

With OpenSSH, a signature problem ends in Permission denied (publickey). A key exchange problem ends in Unable to negotiate, followed by no matching key exchange method found. We reproduced both on a local test server, described in the engineer section, and each exited with code 255.

Other libraries word these errors differently, so search CI logs for both phrases and for any SSH failure on the brownout dates. For the team, a failed fetch on 4 November would stop the day's 25 deploys.

How do you move from an RSA key to Ed25519 for GitHub?

Make a new Ed25519 key, add it to GitHub, test it, then remove the old RSA key. GitHub recommends Ed25519 for new keys whenever possible.

Ed25519 is a modern key type based on elliptic curves, a branch of maths that gives strong keys at small sizes. Its length is fixed, so there is no bit size to get wrong. On the OpenSSH 9.6p1 and 10.2p1 we tested, ssh-keygen with no -t already made an Ed25519 key.

  1. Generate the key

    Run ssh-keygen -t ed25519 -C "[email protected]" and set a passphrase. Make one key per machine, so you can remove one without touching the others.

  2. Load it into the agent

    Run ssh-add ~/.ssh/id_ed25519. The SSH agent is a helper program that holds unlocked keys, so you type the passphrase once.

  3. Upload only the public half

    Add the .pub file to GitHub as an account key, or as a deploy key tied to one repository.

  4. Test, switch and clean up

    Run ssh -T [email protected], point the CI job at the new key, then delete the old RSA key from GitHub.

If a system still needs RSA, GitHub's docs show ssh-keygen -t rsa -b 4096 for legacy systems that do not support Ed25519. That size clears the 3072-bit rule.

What to do with each machine

Follow one machine at a time. Notice that changing the key type is the fallback, used only when the client cannot be upgraded.

Diagram connections:

  • Uses Git over SSH? to Not affected (No: HTTPS remote)
  • Uses Git over SSH? to At or above table version? (Yes)
  • At or above table version? to Keep the key and retest (Yes)
  • At or above table version? to Can you upgrade it? (No)
  • Can you upgrade it? to Upgrade the client (Yes)
  • Can you upgrade it? to Switch to Ed25519 (No)
  • Upgrade the client to Keep the key and retest (Then retest)
  • Uses Git over SSH?: Check the remote with git remote -v
  • Not affected: HTTPS remotes are outside this change
  • At or above table version?: Compare with GitHub's minimum versions
  • Keep the key and retest: Confirm with ssh -vvvT before each brownout
  • Can you upgrade it?: Library, CI plugin or container image
  • Upgrade the client: It then signs with rsa-sha2 by default
  • Switch to Ed25519: Or ECDSA, if the old software supports it

By 28 October, the team's list is clear. The build server runs a newer JSch, the Windows box runs PuTTY 0.82, the bot's Go package is upgraded, and the deploy-key script makes Ed25519 keys.

Why does ssh -Q sig still list ssh-rsa on a safe client?

Because ssh -Q sig lists what your OpenSSH build can do, not what it offers by default. OpenSSH 9.6p1, 9.9p1 and 10.2p1 all listed ssh-rsa there in our tests, and none offered it by default.

OpenSSH 8.8, released on 26 September 2021, disabled RSA signatures using SHA-1 by default. To see what your client will really offer, print its effective settings with ssh -G, which reads your config files and exits without connecting.

bash
# What this build knows: ssh-rsa appears even on new versions
ssh -Q sig | grep rsa

# What it will offer to github.com after reading your config files
ssh -G github.com | grep -iE '^(pubkeyacceptedalgorithms|kexalgorithms) '

On a clean OpenSSH 9.6p1 install, the pubkeyacceptedalgorithms line ends with rsa-sha2-512,rsa-sha2-256 and has no plain ssh-rsa. If ssh-rsa shows up there, a config file added it.

An appended ssh-rsa is harmless for GitHub; a replaced list is not

The OpenSSH 8.8 notes suggested PubkeyAcceptedAlgorithms +ssh-rsa as a stopgap for old servers. The plus sign appends ssh-rsa to the end of the default list, so you may still find that line in old config files.

Pause and predict: does that old line break GitHub logins after the removal? In our rehearsal it did not: OpenSSH 9.6p1 still signed with rsa-sha2-512. OpenSSH picks the first RSA recipe in its own list that the server advertises, and the appended ssh-rsa comes last. The line still allows SHA-1 signing with any server that advertises only ssh-rsa.

The server advertises the recipes it accepts in a list called server-sig-algs, and ssh -v prints that list. We confirmed the selection rule in the OpenSSH 10.2p1 source, in the key_sig_algorithm function of sshconnect2.c.

A line without the plus, PubkeyAcceptedAlgorithms ssh-rsa, replaces the whole list. Against the same test server, no recipe on that list was advertised, so the client never offered the key and stopped with Permission denied (publickey).

Which RSA keys can still sign with SHA-1 on GitHub today?

Only older ones. GitHub Docs say RSA keys with a valid_after date before 2 November 2021 may use any signature algorithm. RSA keys from after that date must already use SHA-2.

That rule came from GitHub's 2021 clean-up and became permanent on 15 March 2022, the day DSA keys stopped working. GitHub words the cutoff three ways: valid_after in its Docs and 2021 post, generated in its Docs, and uploaded in the 2021 timeline. Treat it as roughly when the key was added to GitHub.

So the ssh-rsa removal mostly threatens long-lived RSA keys, the kind used as deploy keys on build servers. A newer RSA key used from a SHA-1-only client fails today already. That is why the team's build server still works: its deploy key dates from 2020.

The key exchange removal is different, because it ignores key age. A client that can only do diffie-hellman-group-exchange-sha256 fails with any key, Ed25519 included. In our rehearsal, an Ed25519 key on such a client stopped at Unable to negotiate.

How can you rehearse the GitHub SSH brownout before 4 November?

Point each client at a test SSH server that refuses the two removed algorithms. We ran an OpenSSH 10.2p1 server on our own machine, because our sandbox could not reach github.com over SSH.

bash
# sshd_config lines for a test server that refuses the two removed algorithms.
# This imitates the announced change; it is not GitHub's real configuration.
PubkeyAcceptedAlgorithms ssh-ed25519,ecdsa-sha2-nistp256,rsa-sha2-512,rsa-sha2-256
KexAlgorithms mlkem768x25519-sha256,sntrup761x25519-sha512,[email protected],curve25519-sha256,[email protected],ecdh-sha2-nistp256
Local rehearsal on 19 October 2026: OpenSSH 9.6p1 client unless noted, against an OpenSSH 10.2p1 test server set up as above
Client settingResultExit code
Defaults, RSA keyLogged in, signing using rsa-sha2-5120
PubkeyAcceptedAlgorithms +ssh-rsaLogged in, signing using rsa-sha2-5120
PubkeyAcceptedAlgorithms ssh-rsaPermission denied (publickey)255
KexAlgorithms diffie-hellman-group-exchange-sha256, Ed25519 keyUnable to negotiate: no matching key exchange method found255
OpenSSH 10.2p1 defaults, RSA keyLogged in, kex mlkem768x25519-sha2560

Both failing settings logged in fine against a second test server that still allowed the old algorithms. That is exactly what a brownout exposes: a client that works today and fails once the server stops offering them.

To watch real machines, the team runs a small Python check every night on each build server. It needs Python 3 and the ssh command, and prints only the lines that matter. Debug wording is not a documented interface (as of 19 October 2026), so pin your OpenSSH version if a script parses it.

python
import subprocess
import sys

# Nightly check: which recipes does this machine use with GitHub?
# Extra ssh arguments can be passed; the default target is [email protected].
args = sys.argv[1:] or ["[email protected]"]
result = subprocess.run(
    ["ssh", "-vvvT", "-o", "ConnectTimeout=10", *args],
    stdin=subprocess.DEVNULL, capture_output=True, text=True, timeout=60,
)
problems = ("Unable to negotiate", "Permission denied", "timed out",
            "Host key verification failed")
for line in result.stderr.splitlines():
    if "kex: algorithm:" in line:
        print("Key exchange:", line.split("kex: algorithm:")[1].strip())
    if "signing using" in line:
        print("Signature:", line.split("signing using")[1].split()[0])
    if any(p in line for p in problems):
        print("Problem:", line.strip())
print("ssh exit code:", result.returncode)

What just happened? Against our test server, a healthy client printed Signature: rsa-sha2-512 and exit code 0. The ssh-rsa-only client printed a Problem line with Permission denied (publickey) and exit code 255.

Against github.com, a healthy run should end with exit code 1, the code GitHub's docs give for a working ssh -T login. For Java or Go tools that do not use the ssh command, compare library versions with GitHub's table instead.

What does GitHub's 3072-bit minimum for new RSA keys mean?

Any new RSA key uploaded to GitHub after 14 October 2026 must be at least 3072 bits. GitHub says this aligns with 128-bit security requirements, meaning an attack should take about 2 to the power 128 steps. The rule covers new uploads; existing RSA keys need not be replaced.

Bits measure the key's main number, called the modulus; a bigger modulus is harder to break. The ssh-keygen manual says RSA keys default to 3072 bits, and OpenSSH 9.6p1 did that in our test. It still accepted -b 2048 without a warning, so old scripts are the risk.

To check many keys at once, run ssh-keygen -l on a file of public keys. It prints the size first and the type last, one key per line.

bash
ssh-keygen -l -f deploy_keys.pub
# 2048 SHA256:togOT5Tc... old_script_key (RSA)
# 3072 SHA256:8CfLxasU... rsa_default (RSA)
# 256 SHA256:ujCbwkVt... [email protected] (ED25519)

# Show only RSA keys too small for a new GitHub upload
ssh-keygen -l -f deploy_keys.pub | awk '$NF == "(RSA)" && $1 < 3072'

The same command works on an authorized_keys file with option prefixes and comment lines; we checked that on OpenSSH 9.6p1. Ed25519 keys always show 256, because their size is fixed, and ssh-keygen ignored -b 4096 for them.

What is the post-quantum mlkem768x25519-sha256 key exchange?

It is a hybrid key exchange that mixes ML-KEM, a method designed to resist quantum computers, with X25519, a classic elliptic-curve method. GitHub's changelog scheduled it for github.com from 14 October 2026.

Key exchange sets up the secret session key that protects the tunnel. OpenSSH warns that attackers could record traffic now and decrypt it later with a quantum computer, an attack it calls store now, decrypt later.

Hybrid means both methods feed the final session key. OpenSSH says the result is no worse than the classic method alone, even if ML-KEM were completely broken.

Which clients actually pick it

OpenSSH added mlkem768x25519-sha256 in 9.9 and made it the default in 10.0, released in April 2025. RFC 4253 says the client's order decides: the first method on the client's list that the server also supports is chosen, subject to host key checks.

So in our test, OpenSSH 9.9p1 chose sntrup761x25519-sha512, an older post-quantum hybrid that sits first in its list. OpenSSH 10.2p1 chose mlkem768x25519-sha256. OpenSSH 9.6p1 does not know ML-KEM at all.

bash
# Prints mlkem768x25519-sha256 if your build knows it (OpenSSH 9.9 or later)
ssh -Q kex | grep mlkem

# Shows which key exchange was actually used with GitHub
ssh -vT [email protected] 2>&1 | grep 'kex: algorithm'

OpenSSH 10.1 and later print a WARNING line when a connection uses no post-quantum key exchange. Our 10.2p1 client printed it against a classic-only server; 9.6p1 stayed silent.

You need not do anything for GitHub. GitHub says the addition should not require changes from users, and older clients should fall back automatically.

How do you explain the GitHub SSH RSA deprecation in a system design interview?

Treat it as a breaking change rolled out safely, and show that you can separate the key from the recipe.

  1. Separate the two ideas

    RSA keys stay; the SHA-1 based ssh-rsa signature recipe and one old key exchange go.

  2. Give the dates

    Brownouts on 4 November and 9 December 2026, then removal on 13 January 2027.

  3. Inventory every client

    List laptops, CI runners and bots, and compare each with GitHub's version table.

  4. Name the trade-off

    Upgrading keeps existing keys. Moving to Ed25519 means rotating keys but ends the key size question.

Questions people ask

Do I need to replace my RSA SSH key for GitHub?
Usually not. GitHub's changelog says all RSA keys can sign with all hash algorithms. An existing key keeps working if your client signs with rsa-sha2-256 or rsa-sha2-512. Any new RSA key you upload must be at least 3072 bits, and GitHub recommends Ed25519 for new keys.
Are HTTPS Git remotes affected by the GitHub SSH changes?
Mostly not. GitHub says that if your Git remotes start with https, nothing here affects you. The exception is the 3072-bit rule, which also applies to RSA keys you upload to sign commits. Logins are affected only for SSH and the unauthenticated Git protocol on GitHub Enterprise Server. Run git remote -v to see which kind each repository uses.
What time do the GitHub SSH brownouts start?
As of 19 October 2026, GitHub has not published times of day or durations. The changelog gives only the dates, 4 November and 9 December 2026. Treat any SSH failure on those days as a likely sign of an old client, and check it with ssh -vvvT.
Will my Ed25519 or ECDSA key keep working?
Yes, for the signature part. GitHub says all Ed25519 and ECDSA keys it supports are strong and will keep working for the indefinite future. The key exchange removal still applies, so a client that only knows diffie-hellman-group-exchange-sha256 fails with any key type.
Does GitHub Enterprise Server get the same SSH changes?
Yes, through its releases. The changelog says the mlkem768x25519-sha256 key exchange arrives in GitHub Enterprise Server 3.24, and the other changes in 3.25. As of 19 October 2026 neither is released; the newest is 3.22. Your admins decide when to upgrade.
Do I need to configure mlkem768x25519-sha256 in my SSH client?
No. GitHub says the addition should not require changes from users, and older clients should fall back to an older key exchange. OpenSSH uses it by default from version 10.0. The kex: algorithm line of ssh -vT [email protected] shows which method was picked.
Why is SHA-1 being removed from SSH signatures?
GitHub says SHA-1 is known to be weak. RFC 8332, which in 2018 defined the SHA-2 recipes for RSA keys in SSH, already called the old ssh-rsa algorithm deficient. OpenSSH stopped offering it by default in version 8.8, released in September 2021.

Sources and further reading

Practise this with Lala

Practise