Preuve de concept en Go démontrant CVE-2026-46595 dans golang.org/x/crypto/ssh, utilisant l'inspection des symboles de binaires dépouillés et des analyses d'images pour vérifier l'utilisation vulnérable de NewServerConn.
https://www.cve.org/CVERecord?id=CVE-2026-46595 correspond à https://pkg.go.dev/vuln/GO-2026-5023 une vulnérabilité dans le symbole NewServerConn de golang.org/x/crypto/ssh comme indiqué dans le second lien.
Ce dépôt contient un programme simple qui démontre une vérification positive de la vulnérabilité.
Un serveur golang.org/x/crypto/ssh minimal épinglé sur x/crypto v0.51.0 (< v0.52.0),
utilisé pour démontrer que go tool nm sur des binaires non strippés fournit à la fois une vérification
positive et négative
go mod tidy
go build ./...
Puisque nous connaissons le symbole vulnérable, vérifions-le. Pour l'instant c'est un binaire non strippé mais nous allons le stripper pour supprimer les tables de symboles et prouver que le symbole vulnérable reste dans la sortie.
file cve-2026-46595-proof
cve-2026-46595-proof: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, Go BuildID=kUaZmGWICI6Buw0K_I7t/L4jXRd3fy2BJy8zNlSYd/lB1_6wYHZLaOLsG0tE26/-FieQlhThdl7AkRj7rl0, BuildID[sha1]=c7ac1dd881dfcaef88a2dd180a8ccb3c5e751e32, with debug_info, not stripped
strings cve-2026-46595-proof | grep golang.org/x/crypto/ssh.NewServerConn
golang.org/x/crypto/ssh.NewServerConn
# ok, maintenant strippons-le et répétons
strip cve-2026-46595-proof
file cve-2026-46595-proof
cve-2026-46595-proof: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, Go BuildID=kUaZmGWICI6Buw0K_I7t/L4jXRd3fy2BJy8zNlSYd/lB1_6wYHZLaOLsG0tE26/-FieQlhThdl7AkRj7rl0, BuildID[sha1]=c7ac1dd881dfcaef88a2dd180a8ccb3c5e751e32, stripped
strings cve-2026-46595-proof | grep -E 'ssh\.(Dial|NewServerConn|NewClientConn|NewControlClientConn)'
golang.org/x/crypto/ssh.NewServerConn
Maintenant, vérifions les binaires livrés dans une image de payload OpenShift.
Extrayons /usr/bin de l'image. --only-files est requis, sinon oc image extract
s'interrompt en cours de route dans la couche lorsqu'il rencontre un lien symbolique tel que /usr/bin/ld.so.
IMG=quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:b4dde8227fb99134f71b50f0707eb7f695cfade43b017da3cbc486c2db854fe1
mkdir -p /tmp/cveimg
oc image extract "$IMG" --path /usr/bin/:/tmp/cveimg/ --only-files
ls -laS /tmp/cveimg | head
Pour ce digest, il s'agit de l'image cluster-config-operator 4.21 :
-rw-r-----. 1 sdodson sdodson 117899168 Feb 24 2026 cluster-config-operator
-rw-r-----. 1 sdodson sdodson 10639741 Feb 24 2026 cluster-config-operator-tests-ext.gz
Voyons contre quelle version de x/crypto il a été compilé :
$ go version -m /tmp/cveimg/cluster-config-operator | grep -E 'go1|x/crypto'
/tmp/cveimg/cluster-config-operator: go1.24.13 (Red Hat 1.24.13-1.el9_6) X:strictfipsruntime
dep golang.org/x/crypto v0.40.0
v0.40.0 est inférieure à toutes les versions corrigées, donc les scanners de version de module le signalent. Appliquons maintenant la vérification de symbole. Outre GO-2026-5023, d'autres vulnérabilités de golang.org/x/crypto sont corrigées dans v0.55.0 et v0.56.0, donc vérifions tous leurs symboles vulnérables en une seule fois :
GO-2026-5023 => ssh.NewServerConn GO-2026-6303 => ssh.NewServerConn à nouveau GO-2026-6354 => ssh.Dial ssh.NewClientConn ssh.NewControlClientConn ssh.NewServerConn GO-2026-6355 => ssh.Dial ssh.NewClientConn ssh.NewControlClientConn ssh.NewServerConn
Le binaire tests-ext est livré compressé en gzip, donc décompressons-le d'abord et vérifions les deux :
gzip -dc /tmp/cveimg/cluster-config-operator-tests-ext.gz > /tmp/cveimg/cluster-config-operator-tests-ext
strings /tmp/cveimg/cluster-config-operator{,-tests-ext} \
| grep -E 'ssh\.(Dial|NewServerConn|NewClientConn|NewControlClientConn)'
Aucune sortie, youpi pas de vulnérabilité ! Vérifions que le grep n'est pas silencieux pour la raison banale qu'il n'y a aucun symbole à comparer :
$ go tool nm /tmp/cveimg/cluster-config-operator | wc -l
150240
$ go tool nm /tmp/cveimg/cluster-config-operator | grep -c golang.org/x/crypto/ssh
0
$ go tool nm /tmp/cveimg/cluster-config-operator-tests-ext | wc -l
24607
$ go tool nm /tmp/cveimg/cluster-config-operator-tests-ext | grep -c golang.org/x/crypto
39
Donc x/crypto est bien lié, l'éditeur de liens a simplement supprimé tout x/crypto/ssh parce que
rien ne l'atteint.
Cela devrait être reproductible sur les autres images de payload ; la seule variation par image est
l'emplacement des binaires et s'ils sont compressés comme le -tests-ext.gz ci-dessus.
Notez que les binaires de test tels que *-tests-ext sont livrés dans les images même s'ils ne sont
sur aucun chemin d'exécution. Là où ils tirent effectivement x/crypto/ssh (le k8s-tests-ext de kubernetes
lie ssh.NewClientConn pour ses helpers SSH e2e), cela reste hors du chemin d'exécution du
composant en cours d'exécution. Quoi qu'il en soit, nous travaillerons à supprimer les binaires de test des images car ils
les rendent plus volumineuses et ralentissent des choses comme les pulls d'images.
Ce qui suit a été généré par Claude lors de la création des binaires de cas de test positifs, non nécessaire pour la preuve mais je l'ai laissé.
Ce n'est pas nécessaire pour prouver que la vulnérabilité existe, ce qui précède le démontre déjà mais n'hésitez pas à le faire également.
go run . -addr 127.0.0.1:2222 -user demo -password demo
Puis, dans un autre terminal :
ssh -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null [email protected]
Le mot de passe est demo. La session affiche un message d'accueil et renvoie l'entrée en écho.
Une nouvelle clé d'hôte ed25519 est générée à chaque démarrage, donc rien n'est écrit sur le disque.
À la v0.51.0, govulncheck signale 10 vulnérabilités atteignables dans
golang.org/x/crypto/ssh, toutes tracées via main.go →
ssh.NewServerConn (GO-2026-5018 trace également via ssh.NewSignerFromKey).
go get golang.org/x/[email protected]
go mod tidy
govulncheck ./...
v0.52.0 élimine la plupart d'entre elles, mais trois nécessitent des versions plus récentes : GO-2026-6303 est corrigée dans v0.55.0, et GO-2026-6354 / GO-2026-6355 dans v0.56.0. Une analyse à la v0.56.0 devrait revenir propre.