● Medium · CVSS 5.3

CVE-2026-46598: the ssh/agent ed25519 panic in golang.org/x/crypto, and how to upgrade to v0.52.0

By the Sai Kiran Pandrala · Reviewed and edited by Sai Kiran Pandrala, Editor

⚡ At a glance
SeverityMedium. CVSS 3.1 base 5.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L)
Actively exploited?No. Not on CISA KEV; CISA SSVC Exploitation: none
Affectedgolang.org/x/crypto < 0.52.0 (module path golang.org/x/crypto/ssh/agent)
Fixed ingolang.org/x/crypto v0.52.0
Type (CWE)CWE-129: Improper Validation of Array Index (manifests as a denial-of-service panic)

Exploitation status

CVE-2026-46598 is not on the CISA Known Exploited Vulnerabilities catalog, and CISA's own SSVC decision record scores it Exploitation: none. The Go security team assigned it Go advisory GO-2026-5033 and a CVSS 3.1 base of 5.3 (Medium). So this is a real bug worth fixing, but it is not a five-alarm fire and nobody should be reading "Critical" anywhere on this page.

No public exploit or proof-of-concept beyond the upstream test case is referenced in the advisory. The interesting nuance is the SSVC "Automatable: yes" flag: because the trigger is a single malformed wire message rather than a multi-step chain, a script could spray it at many ServeAgent listeners cheaply. That raises the nuisance ceiling for an availability bug, even though the worst outcome is still just a crashed process.

What is CVE-2026-46598?

CVE-2026-46598 is a denial-of-service flaw in the Go module golang.org/x/crypto, specifically the ssh/agent package. For certain crafted inputs the code built an ed25519.PrivateKey by casting malformed wire bytes directly into the key type instead of validating the length first. When that under-sized slice is later used for a signing or marshalling operation, the standard library indexes past the end of it and the program panics. The CNA (the Go team) classifies it as CWE-129, improper validation of an array index.

In plain terms: feed the agent a key blob that claims to be an ed25519 key but is the wrong size, and the Go process handling it dies. There is no memory disclosure and no way to forge a signature; the entire impact is the crash. That is exactly what the CVSS vector says: A:L with confidentiality and integrity both NONE.

Why this CVE matters

It matters because of where golang.org/x/crypto/ssh/agent tends to live, not because of the score. This package backs SSH agent servers and agent-forwarding code inside Go programs. Think jump hosts, CI runners, bastion services, Teleport-style access proxies, and anything that calls ServeAgent to expose an agent over a socket. The reporter credit goes to NCC Group Cryptography Services sponsored by Teleport, which tells you the realistic target shape: a long-lived agent process that accepts key material from clients you do not fully trust.

The affected routines are parseEd25519Cert, parseEd25519Key, ForwardToAgent and ServeAgent. If your program calls ServeAgent and a client (or a forwarded upstream) can hand it ed25519 key bytes, an attacker can panic that goroutine and, depending on how you recover, take down the listener. A short-lived CLI that only signs with its own on-disk keys barely feels this. A multi-tenant agent endpoint feels it a lot.

Am I affected? Detect the vulnerable version

You are affected if any binary you ship or run imports golang.org/x/crypto at a version below 0.52.0. The vulnerability lives in the module, so the question is "which version of the dependency did this binary compile against", not "which OS am I on". Three concrete ways to check, from your repo or a built artifact:

# A. From a module's source tree. Show the resolved x/crypto version.
go list -m golang.org/x/crypto
#   golang.org/x/crypto v0.51.0   <- anything < v0.52.0 is vulnerable

# B. Find every module in a multi-module workspace that pulls it in,
#    and see WHY (which of your deps requires it).
go mod why golang.org/x/crypto
go mod graph | grep golang.org/x/crypto

# C. Inspect an already-built binary you cannot rebuild from source yet.
#    Go stamps module versions into the binary; read them back:
go version -m ./your-binary | grep golang.org/x/crypto
#   dep  golang.org/x/crypto  v0.51.0  h1:...

Option C is the one most people forget. If you inherited a binary from a vendor or an old CI artifact, go version -m reads the embedded build info without any source at all. If it prints a version below v0.52.0, that artifact is affected and needs a rebuild. You cannot hot-patch a compiled Go binary.

How to fix CVE-2026-46598

The fix is to upgrade the dependency to golang.org/x/crypto v0.52.0 and rebuild. There is no OS package, no MSI, no apt or dnf update that fixes this. The vulnerable code is statically linked into your Go binary, so you bump the module and recompile. Here is the exact sequence.

  1. In each Go module that depends on x/crypto, upgrade to v0.52.0.
  2. Run go mod tidy so the upgrade propagates to go.mod and go.sum.
  3. Rebuild every binary produced from that module. The old binary keeps the old, vulnerable copy of x/crypto until you recompile it.
  4. Redeploy the rebuilt binaries and restart the services so the patched code is actually running.
  5. Verify the embedded version, then confirm your agent listeners survive a malformed key (see verification below).

Upgrade the module to v0.52.0

# CVE-2026-46598: golang.org/x/crypto < 0.52.0 is affected. Fixed in v0.52.0.
# Go advisory: https://pkg.go.dev/vuln/GO-2026-5033

# 1. Show the current resolved version.
go list -m golang.org/x/crypto

# 2. Upgrade x/crypto to the patched release. Note the correct module path:
#    it is golang.org/x/crypto, NOT a github.com/... mirror.
go get golang.org/x/[email protected]

# 3. Reconcile go.mod / go.sum and rebuild.
go mod tidy
go build ./...

# 4. Confirm the resolved version is now v0.52.0 or later.
go list -m golang.org/x/crypto

If a transitive dependency is the thing dragging in an old x/crypto, the go get golang.org/x/[email protected] still works, because Go's minimum-version selection will raise the whole graph to v0.52.0. You can prove it stuck with go mod why golang.org/x/crypto afterwards. Avoid the temptation to add a replace directive pointing at a fork; for a clean upstream release like this, a straight version bump is the maintainable path.

Confirm with govulncheck (the Go-native scanner)

The right scanner for a Go module flaw is govulncheck, not a generic host scanner. It reads the Go vulnerability database and, crucially, does call-graph analysis, so it will tell you whether your code actually reaches the vulnerable functions, not just whether the module is present.

# Install (or update) the official Go vulnerability scanner.
go install golang.org/x/vuln/cmd/govulncheck@latest

# Scan your module's source. Before the fix this reports GO-2026-5033.
govulncheck ./...

# Scan an already-built binary instead of source:
govulncheck -mode=binary ./your-binary

Before you upgrade, expect govulncheck to print GO-2026-5033 with a trace into parseEd25519Key / ServeAgent if your code is actually exposed. After the upgrade and rebuild, that finding should be gone. If govulncheck reports the module is present but no symbol is reachable, your exposure is lower, but still rebuild, because reachability analysis can miss reflection and dynamic dispatch.

Verify the fix actually landed

# CVE-2026-46598 verification checklist.

# 1. The rebuilt binary embeds v0.52.0 (or later):
go version -m ./your-binary | grep golang.org/x/crypto
#   expect: dep golang.org/x/crypto v0.52.0 ...

# 2. govulncheck no longer reports GO-2026-5033:
govulncheck -mode=binary ./your-binary

# 3. Functional check: confirm the agent listener no longer dies on a bad key.
#    Restart the service, then watch for panic stack traces while you exercise it.
journalctl -u your-go-service --since "10 minutes ago" | grep -i "panic\|ed25519"

The single most common mistake here is upgrading go.mod but redeploying a stale binary. The module version in source means nothing until you recompile and ship; go version -m on the artifact that is actually running in production is the only check that proves it.

If you cannot rebuild immediately

There is no upstream config flag that disables the bad code path, so the only real mitigations are about reducing who can reach the parsing routines. Ranked by how much they actually help:

  1. Restrict the agent endpoint. If you run ServeAgent over a network listener, put it behind authentication and an allow-list so only trusted clients can send key material. A Unix-domain socket with tight file permissions is far safer than a TCP listener.
  2. Be careful with agent forwarding. ForwardToAgent exposes you to whatever the upstream side sends. Disable forwarding to or from hosts you do not control until the rebuild ships.
  3. Add panic recovery at the goroutine boundary as a stopgap only. A recover() around the per-connection handler stops one malformed key from taking down the whole listener, but it does not fix the underlying CWE-129 and it can mask other failures. Treat it as a bandage you remove after upgrading.
  4. Do not rely on a WAF. The malformed key rides inside the SSH agent protocol, which a web firewall cannot parse. Network filters that only understand HTTP give you nothing here.

Full fix path in order

Because the only impact is availability, there is no credential-rotation or data-breach cleanup to do here. If you saw crash loops on an exposed agent listener before patching, that is worth a note in your incident log, but a panic alone does not imply key compromise.

Frequently asked questions

What is the fixed version for CVE-2026-46598?

golang.org/x/crypto v0.52.0 fixes it. Every version below 0.52.0 is affected. Run go get golang.org/x/[email protected], then go mod tidy, and rebuild every binary that imports golang.org/x/crypto/ssh/agent.

Is CVE-2026-46598 a critical, exploitable vulnerability?

No. It is rated Medium, CVSS 5.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L). The only impact is availability: a crafted ed25519 wire key makes the parsing code panic and crash the process. There is no confidentiality or integrity impact, CISA's SSVC rates Exploitation as none, and it is not on the CISA KEV catalog.

Which code paths in golang.org/x/crypto are affected?

The named routines are parseEd25519Cert, parseEd25519Key, ForwardToAgent and ServeAgent. A program that runs an agent server (ServeAgent) or forwards to an agent (ForwardToAgent) and parses attacker-supplied ed25519 key bytes can be crashed. A CLI that only uses its own local keys is far less exposed.

Can a WAF or firewall mitigate CVE-2026-46598?

Not meaningfully. The vulnerable data travels inside the SSH agent protocol channel, not as inspectable HTTP, so a web firewall never sees it. If you cannot rebuild immediately, restrict which clients can reach the agent socket or ServeAgent listener. The durable fix is upgrading the module and recompiling.

Other flaws in this area worth reviewing while you patch this one:

References


This guide was assembled from the Go security team's CVE record and the GO-2026-5033 advisory. The CVSS 5.3 score and SSVC "Exploitation: none" reading come from the CISA ADP vulnrichment in that record. Always confirm against the upstream advisory before applying changes in production.

What an attacker actually needs (precondition breakdown)

Reading the CVSS vector AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L line by line tells you exactly how exposed you are, and it is more useful than the single number:

So the honest risk statement is: an unauthenticated client that can reach a Go SSH agent server built on x/crypto below v0.52.0 can crash that process by sending a wrong-sized ed25519 key. No more, no less. Plan your patch window around an availability bug, not a breach.