Tested fix · Updated

GitHub's SSH change: "key is too short", the 4 November brownout, and the error each old client prints

GitHub is tightening SSH in three steps, and the first one is already live. Since 14 October 2026 it refuses new RSA keys shorter than 3072 bits. On 4 November it switched off two old algorithms for a day as a trial, and it does so again on 9 December. On 13 January 2027 it removes them for good. Git's own ssh command is usually OpenSSH, which GitHub lists as fine from 7.2p1. In our test against a server set up like github.com after the change, what broke was software that talks SSH through a library, when it was old and used an RSA key: Java with JSch (also under JGit), Go with x/crypto/ssh (also under go-git), Node with ssh2, Python with paramiko, PuTTY's plink and curl built on libssh2.

None of these programs tells you why. Most print an ordinary login failure; old paramiko prints a complaint about the key file instead. This page lists the messages they print, says which part of GitHub's change causes each one, and gives the version or key type that fixes it.

The dates

DateWhat GitHub changes
14 October 2026New RSA keys must be at least 3072 bits. Keys already on GitHub are not affected by the size rule.
4 November 2026First brownout: ssh-rsa signatures (RSA with SHA-1) and the diffie-hellman-group-exchange-sha256 key exchange were switched off for the day.
9 December 2026Second brownout, same change.
13 January 2027Both are removed permanently.

GitHub has not said at what hours the brownouts start or how long they last. On 4 November we checked github.com every 30 minutes from midnight UTC and first saw the change at 08:30 UTC; at 08:00 it was not there yet. We last saw it at 21:30 UTC, and by 22:00 the old algorithms were back, so from where we checked it ran from about 08:30 to 22:00 UTC. Only Git over SSH is affected; GitHub says remotes that start with https:// are not. On GitHub Enterprise Server the same changes come with version 3.25.

Get the next date as a warning in your build: one workflow step that reads your repository on GitHub's runner and sends nothing from it to us.

Find your error

What you seePrinted bySection
key is too short. GitHub recommends using ssh-keygen to generate a RSA key of at least 3072 bits.GitHub, when you add the key (since 14 October)Key too short
com.jcraft.jsch.JSchException: Auth failJava, original JSch 0.1.55JSch
org.eclipse.jgit.api.errors.TransportException: ssh://…: Auth failJava, JGit 5.13.3 on JSch 0.1.55JSch
ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remainGo, old golang.org/x/crypto/ssh, and go-git v5.4.2Go
All configured authentication methods failedNode.js, ssh2 0.8.9 and 1.0.0Node ssh2
SSHException: not a valid OPENSSH private key filePython, paramiko 2.4.2, RSA key fileparamiko
SSHException: encountered RSA key, expected OPENSSH keyPython, paramiko 2.8.1, RSA key fileparamiko
Server refused our key, then FATAL ERROR: … No supported authentication methods available (server sent: publickey)PuTTY plink 0.70 and 0.73PuTTY
curl: (67) Authentication failurecurl with libssh2 1.10.0 (Debian 12)libssh2
curl: (2) Failure establishing ssh sessioncurl with libssh2 1.8.0 (CentOS 7)libssh2

The client errors in this table came from our own test against a server set up like github.com after the removal. During the 4 November brownout we ran the same clients against github.com itself (all but JGit and go-git), and each printed the same last line as here. Old paramiko first went quiet for about 40 seconds. Every client message here except curl: (2) also appears for ordinary reasons, such as a key that was never added to GitHub; curl: (2) comes before the login. Is it this change? shows how to tell.

"key is too short" when you add a key

Since 14 October 2026 GitHub refuses a new RSA key under 3072 bits, both as an account SSH key and as a deploy key. Through the API, which is what Terraform uses, one public report quotes the refusal like this:

Error: POST https://api.github.com/repos/<org>/<repo>/keys: 422 Validation Failed
[{Resource:PublicKey Field:key Code:custom Message:key is too short. GitHub recommends
using ssh-keygen to generate a RSA key of at least 3072 bits.}]

Keys that are already on GitHub keep working, so nothing fails until someone adds or rotates a key. That makes this easy to miss: an environment created next month, or a key rotated on schedule, fails long after the change.

Terraform. The hashicorp/tls provider's tls_private_key makes 2048-bit RSA keys unless you set rsa_bits. Any module that passes such a key to github_repository_deploy_key or github_user_ssh_key now fails on new keys. The fix is one of these:

resource "tls_private_key" "deploy" {
  algorithm = "ED25519"
}
resource "tls_private_key" "deploy" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

GitHub recommends Ed25519 for new keys. If you choose ECDSA instead, set ecdsa_curve = "P256": the provider's default curve is P224, for which it produces no OpenSSH public key.

Changing algorithm or rsa_bits on an existing tls_private_key replaces the key. Terraform then creates a new key pair, and every system that holds the old private key, such as a CD tool's repository secret, needs the new one.

Command line. Make a new key with either of these:

ssh-keygen -t ed25519 -f ~/.ssh/github_ed25519
ssh-keygen -t rsa -b 4096 -f ~/.ssh/github_rsa4096

Before you pick RSA, check the client that will use the key. Since 15 March 2022, GitHub has accepted only SHA-2 signatures from RSA keys added on or after 2 November 2021. By that rule, a new RSA key of any size will not work from the old clients in the sections below, starting the day you add it, not on 4 November. For those clients use Ed25519, or ECDSA for the original JSch 0.1.55, which cannot load Ed25519 keys. Or upgrade the client.

Java: com.jcraft.jsch.JSchException: Auth fail

com.jcraft.jsch.JSchException: Auth fail
	at com.jcraft.jsch.Session.connect(Session.java:519)

Cause: the original JSch from JCraft (com.jcraft:jsch) has had no release since 0.1.55 in 2018. In our test it signed with an RSA key using SHA-1 (ssh-rsa), which GitHub is removing.

JGit 5.13.3 with its JSch transport on JSch 0.1.55 failed the same way. JSch's error is at the bottom of the chain (stack frames left out):

org.eclipse.jgit.api.errors.TransportException: ssh://git@…: Auth fail
Caused by: org.eclipse.jgit.errors.TransportException: ssh://git@…: Auth fail
Caused by: com.jcraft.jsch.JSchException: Auth fail

The same JGit connected with the maintained fork below in place of com.jcraft:jsch, and with JGit's Apache MINA sshd transport (org.eclipse.jgit.ssh.apache, sshd 2.7.0 in our test).

Fix: replace the dependency with the maintained fork, com.github.mwiede:jsch. Its README calls it a drop-in replacement: you change the dependency coordinates, not the code. In our test 0.1.66 and 2.28.8 passed with an RSA key; GitHub's minimum is 0.1.66.

<dependency>
  <groupId>com.github.mwiede</groupId>
  <artifactId>jsch</artifactId>
  <version>2.28.8</version>
</dependency>

If something else pulls in com.jcraft:jsch, exclude it there. Run mvn dependency:tree -Dincludes=com.jcraft or gradle dependencies to find out which dependency brings it in.

Key workaround: an ECDSA key worked with JSch 0.1.55 in our test. An Ed25519 key does not, because 0.1.55 cannot load it.

Go: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain

ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain

Cause: golang.org/x/crypto/ssh from November 2021 (v0.0.0-20211117183948-ae814b36b871 in our test) signed with an RSA key using SHA-1.

Fix: upgrade the module and rebuild.

go get golang.org/x/crypto@latest
go mod tidy

GitHub's table asks for v0.16.0. In our test v0.1.0 and v0.15.0 also passed, so a binary built with one of those is probably not your problem. Check what a built binary contains with go version -m ./yourbinary | grep x/crypto.

Key workaround: Ed25519 and ECDSA keys worked with the old version in our test.

go-git v5.4.2, built with the x/crypto it requires (April 2021), printed the same message for both List and PlainClone with an RSA key. go-git v5.19.3 connected:

go get github.com/go-git/go-git/v5@latest
go mod tidy

Node.js: All configured authentication methods failed

Error: All configured authentication methods failed

This is the error the Client emits, with level: 'client-authentication'.

Cause: ssh2 0.8.9 and 1.0.0 signed with an RSA key using SHA-1 in our test. GitHub's version table does not list ssh2.

Fix: npm install ssh2@latest. 1.17.0 passed in our test. If ssh2 comes in through another package, npm ls ssh2 shows which one, and an overrides entry in package.json can force a newer version, if that package works with it.

Key workaround: Ed25519 and ECDSA keys worked with 0.8.9 and 1.0.0 in our test.

Python paramiko: not a valid OPENSSH private key file or encountered RSA key, expected OPENSSH key

This is the most misleading one. With a PEM-format RSA key (its first line contains BEGIN RSA PRIVATE KEY; ssh-keygen -m PEM writes this format) passed as key_filename=, SSHClient.connect in paramiko 2.4.2 printed:

paramiko.ssh_exception.SSHException: not a valid OPENSSH private key file

and paramiko 2.8.1 printed:

paramiko.ssh_exception.SSHException: encountered RSA key, expected OPENSSH key

No login error appears, and nothing in either message mentions ssh-rsa. The traceback shows why: paramiko tries the key file as each key type it knows, and after the server refused the RSA signature, the last try read the file as an Ed25519 key. That parse error is the one you see. Our test server's log showed the real refusal, signature algorithm ssh-rsa not in PubkeyAcceptedAlgorithms; GitHub does not show you its log.

Against github.com during the 4 November brownout, paramiko 2.4.2 and 2.8.1 printed the same two messages, but only after about 40 seconds with no output (38.6 and 41.2 seconds), where on 2 November they failed in 2 and 5 seconds. So the job looks hung before the key-file error appears. The wait is likely paramiko's 30-second login timeout. A job with a shorter timeout of its own stops before any message: our first two runs, with a 25-second limit, ended with no output at all.

We did not test an RSA key in the newer OpenSSH format (its first line contains BEGIN OPENSSH PRIVATE KEY), or keys that paramiko finds through an SSH agent or look_for_keys. Those may print something else.

Cause: paramiko 2.4.2 and 2.8.1 signed with an RSA key using SHA-1 in our test. GitHub's version table does not list paramiko.

Fix: pip install -U paramiko. 2.9.0 is the first version that passed in our test, and 5.1.0 passed too.

Key workaround: Ed25519 and ECDSA keys worked with 2.4.2 and 2.8.1 in our test.

libssh2: curl: (67) Authentication failure and curl: (2) Failure establishing ssh session

We tested libssh2 through curl. Other programs built on libssh2 word their errors their own way, so check the libssh2 version rather than the message.

libssh2 1.10.0 (Debian 12's package) failed with an RSA key, because it signed with SHA-1:

curl: (67) Authentication failure

With curl -v the lines before it include:

* SSH public key authentication failed: Username/PublicKey combination invalid

Ed25519 and ECDSA keys worked with it. Debian 12 has long-term support until 30 June 2028, so this one will be around.

libssh2 1.8.0 (CentOS 7's package) failed before it reached the login, with every key type:

curl: (2) Failure establishing ssh session

It printed this line against github.com during the 4 November brownout. On 2 November the same command got past the key exchange and failed at the login instead, with curl: (67) Authentication failure, because our test key is not registered with GitHub. The key exchange GitHub is removing is the only one this version shares with github.com. During the brownout github.com also stopped offering an ssh-rsa host key, the only github.com host-key type this version can check. A different key does not help, because 1.8.0 cannot load Ed25519 or ECDSA keys either. Move that job to a newer system.

Fix: libssh2 1.11.1 (Debian 13's package) passed in our test; GitHub's minimum is 1.11.0. curl -V | grep -o 'libssh2/[0-9.]*' shows the version your curl uses.

Is it this change, or something else?

All of the client messages above except curl: (2) also appear when the key was never added to GitHub, or the program is reading a different key. Three checks separate the two:

  1. Try the same key with OpenSSH. GitHub lists OpenSSH 7.2p1 and later as fine.

    ssh -i ~/.ssh/your_key -o IdentitiesOnly=yes -T git@github.com

    If it greets you with Hi …! You've successfully authenticated, but GitHub does not provide shell access., GitHub accepts the key, and the program that fails is the suspect. A PuTTY .ppk key needs converting first: puttygen your_key.ppk -O private-openssh -o your_key.

  2. Look at the date. If it fails on 4 November or 9 December and works the day before and after, the brownout is the likely cause.

  3. Look at the version. Compare the client's version with the passing versions in its section.

Check before 9 December

Only remotes that do not start with https:// matter, and git remote -v lists them. ssh-add -l shows the type of each key in your SSH agent, in brackets at the end of its line; ssh-keygen -lf followed by a key file does the same for a key on disk. Ed25519 and ECDSA avoid the SHA-1 RSA change; the client still needs a supported key exchange. So whatever the key, find what makes the connection and its version. Run each of these where that tool or project is installed:

git remote -v
ssh-add -l
pip show paramiko | grep Version
npm ls ssh2
go list -m golang.org/x/crypto
plink -V
curl -V | grep -o 'libssh2/[0-9.]*'

For Java, look for jsch in mvn dependency:tree or gradle dependencies. A program that bundles its own SSH library will not show up in any of these.

A working RSA connection today does not tell you whether the key is affected. The SHA-1 part of the change newly matters only for RSA keys added to GitHub before 2 November 2021, and from outside you cannot tell a key's age from a connection that works. Your GitHub settings show when each key was added; the client's version tells you the rest.

The brownout dates are also in our Breakage Calendar.

Text for your ticket

Affected? Paste this into your team's work item. It ends with a link back to this page.

In the box: Ctrl+A (⌘A on a Mac), then copy. On a phone: press and hold, then Select All.

After 13 January

Get the next date as a warning in your build

GitHub's ssh-rsa removal on 13 January 2027 is one date. For it, the step marks a repository that depends on ssh2, paramiko, JSch or Go's x/crypto/ssh as “may hit”, because only old clients break. The Breakage Calendar has more dates that a repository's files can show: image tags that move, runtimes that reach end of life, retired CI runners, model shutdowns. One workflow step runs each date's search on your repository and warns on the line it affects, with the days left and, where we have one, a link to a tested fix. It reads your files on the runner and sends nothing about them to us; its warnings stay with the workflow run on GitHub.

The step's log on a small test repository, 13 November 2026
  • · in 6 dayspostgres:latest becomes 19compose.yaml:3
  • · in 17 daysClaude Sonnet 4.5 retired from the Claude APIapp/summarize.py:3

Save this as .github/workflows/dated-breaks.yml:

name: Dated breaks
on:
  pull_request:
  schedule:
    - cron: '17 6 * * 1'
permissions:
  contents: read
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: CyberNative-AI/dated-break-check@d0f1d1cd5b0c57e873a4f4acc4ea1912547785dd # v1.0.0
        with:
          fail-within: ${{ github.event_name == 'schedule' && '14' || '' }}

Pull requests get warnings. A date whose search finds the exact line, such as an image tag or model name, also fails the Monday run once it is 14 days away or fewer, so GitHub's own failed-run notice reaches you. For 13 January the step can only say “may hit”, so the warning stays on pull requests and in the run log and never fails a run. A new date on the calendar reaches you without a change to your code.

How we tested

On 21 October 2026 we set our own OpenSSH 10.0p2 server to github.com's SSH algorithm lists as read that day, then removed ssh-rsa signatures and diffie-hellman-group-exchange-sha256. We connected from 35 client stacks with RSA (3072-bit), ECDSA and Ed25519 keys, twice each. 32 stacks could log in before the removal. After it, 10 of the 32 failed. Every failure involved the RSA key; none of the stacks failed with an ECDSA or Ed25519 key it could load. The one key-exchange failure, CentOS 7's libssh2 1.8.0, can load no other key type. All five OpenSSH clients we tried kept working, as did the newest versions of every library we tried.

On 23 October we ran 29 configurations again against the same stand-in, twice each, this time through each library's normal top-level call, to record the exact messages on this page, and added JGit and go-git. All 10 failing stacks failed again, JGit on JSch 0.1.55 and go-git v5.4.2 failed too, and every newer version connected. The 24 results that could be compared with the 21 October run all matched. The RSA test key was 3072-bit, in PEM format.

This was our stand-in, not GitHub's server. GitHub's real servers could negotiate differently, so on 4 November we also read github.com's own algorithm lists every 30 minutes from midnight UTC. From 08:30 UTC until about 22:00 UTC, github.com no longer offered diffie-hellman-group-exchange-sha256, no longer listed ssh-rsa among the signature types it accepts, and no longer offered an ssh-rsa host key; its Ed25519, ECDSA and SHA-2 RSA host keys remained.

We then connected from the failing stacks above, except JGit and go-git, with an RSA key that is not registered with GitHub. Each printed the same last line as against our stand-in, and none showed a message from GitHub, such as a notice or a link. Every other client we tested chose an Ed25519 or ECDSA host key, so none of them failed at the host-key step. libssh2 1.8.0 is the exception: the only github.com host-key type it can check is ssh-rsa, so during the brownout it shared neither a key exchange nor a host-key type with github.com.

Because GitHub did not know our key, any message it shows only after it recognises a registered key is still untested. We will check again during the 9 December brownout. We did not test Windows clients, TortoiseGit, TeamCity, libgit2 builds, Dropbear or ssh-agent setups. Executed by us; not independently reproduced.

Sources: GitHub changelog, "Security improvements for SSH", 22 September 2026; GitHub blog, "Improving Git protocol security on GitHub" (SHA-2 only for RSA keys added from 2 November 2021); GitHub Docs, "Testing your SSH connection"; tls_private_key documentation; the 422 report; the maintained JSch fork.