Prueba de concepto en Go que demuestra CVE-2026-46595 en golang.org/x/crypto/ssh, utilizando inspección de símbolos de binarios sin símbolos y escaneos de imágenes para verificar el uso vulnerable de NewServerConn.
https://www.cve.org/CVERecord?id=CVE-2026-46595 es https://pkg.go.dev/vuln/GO-2026-5023 una vulnerabilidad en el símbolo NewServerConn de golang.org/x/crypto/ssh como se indica en el segundo enlace.
Este repositorio contiene un programa simple que demuestra una comprobación positiva de la vulnerabilidad.
Un servidor mínimo de golang.org/x/crypto/ssh fijado a x/crypto v0.51.0 (< v0.52.0),
utilizado para demostrar que go tool nm sobre binarios no eliminados (unstripped) proporciona tanto una comprobación positiva como
negativa
go mod tidy
go build ./...
Como conocemos el símbolo vulnerable, lo comprobamos. Ahora mismo es un binario sin eliminar (unstripped) pero lo eliminaremos (strip) para quitar las tablas de símbolos y demostrar que el símbolo vulnerable permanece en la salida.
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, ahora lo eliminamos y repetimos
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
Ahora, vamos a comprobar los binarios incluidos en una imagen de payload de OpenShift.
Extrae /usr/bin de la imagen. --only-files es necesario, de lo contrario oc image extract
aborta a mitad de la capa cuando encuentra un enlace simbólico como /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
Para este digest, esa es la imagen cluster-config-operator de 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
Veamos contra qué versión de x/crypto se 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á por debajo de todas las versiones corregidas, por lo que los escáneres de versión de módulos lo marcan. Ahora aplicamos la comprobación de símbolos. Además de GO-2026-5023 hay otras vulnerabilidades de golang.org/x/crypto corregidas en v0.55.0 y v0.56.0, así que comprobamos todos sus símbolos vulnerables a la vez:
GO-2026-5023 => ssh.NewServerConn GO-2026-6303 => ssh.NewServerConn de nuevo GO-2026-6354 => ssh.Dial ssh.NewClientConn ssh.NewControlClientConn ssh.NewServerConn GO-2026-6355 => ssh.Dial ssh.NewClientConn ssh.NewControlClientConn ssh.NewServerConn
El binario tests-ext se distribuye comprimido con gzip, así que descomprímelo primero y comprueba ambos:
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)'
Sin salida, ¡bien, no hay vulnerabilidad! Comprobación de cordura de que el grep no está silencioso por la aburrida razón de que no haya símbolos con los que coincidir:
$ 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
Así que x/crypto está genuinamente enlazado, el enlazador simplemente descartó todo x/crypto/ssh porque
nada llega a él.
Esto debería ser repetible en las otras imágenes de payload; la única variación por imagen es
dónde viven los binarios y si están comprimidos como el -tests-ext.gz de arriba.
Ten en cuenta que los binarios de test como *-tests-ext se distribuyen en las imágenes aunque no estén
en ninguna ruta de ejecución. Donde sí arrastran x/crypto/ssh (el k8s-tests-ext de kubernetes
enlaza ssh.NewClientConn para sus helpers SSH de e2e) sigue estando fuera de la ruta de ejecución del
componente en ejecución. Independientemente de esto, trabajaremos para eliminar los binarios de test de las imágenes porque
las hacen más grandes y ralentizan cosas como las descargas de imágenes.
Lo siguiente fue generado por Claude al crear los binarios del caso de prueba positivo, no es necesario para la prueba pero lo he dejado.
Esto no es necesario para demostrar que la vulnerabilidad existe, lo anterior ya lo demuestra pero siéntete libre de hacerlo también.
go run . -addr 127.0.0.1:2222 -user demo -password demo
Luego, en otra terminal:
ssh -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null [email protected]
La contraseña es demo. La sesión imprime un saludo y devuelve la entrada.
Se genera una nueva clave de host ed25519 en cada inicio, por lo que no se escribe nada en disco.
En v0.51.0, govulncheck informa de 10 vulnerabilidades alcanzables en
golang.org/x/crypto/ssh, todas trazadas a través de main.go →
ssh.NewServerConn (GO-2026-5018 también se traza a través de ssh.NewSignerFromKey).
go get golang.org/x/[email protected]
go mod tidy
govulncheck ./...
v0.52.0 elimina la mayoría de ellas, pero tres necesitan versiones más recientes: GO-2026-6303 se corrige en v0.55.0, y GO-2026-6354 / GO-2026-6355 en v0.56.0. Escanear en v0.56.0 debería salir limpio.