
golang.org/x/crypto/ssh における CVE-2026-46595 を実証する Go の概念実証。ストリップされたバイナリのシンボル検査とイメージスキャンを用いて、脆弱な NewServerConn の使用を検証する。
https://www.cve.org/CVERecord?id=CVE-2026-46595 は https://pkg.go.dev/vuln/GO-2026-5023 です。 2番目のリンクに記載されているとおり、golang.org/x/crypto/ssh の NewServerConn シンボルにおける脆弱性です。
このリポジトリには、脆弱性チェックが陽性となることを示す簡単なプログラムが含まれています。
最小限の golang.org/x/crypto/ssh サーバーを x/crypto v0.51.0(< v0.52.0)に固定したもので、
未ストリップのバイナリに対して go tool nm を実行することで、陽性チェックと陰性チェックの
両方が可能であることを示すために使用されます。
go mod tidy
go build ./...
脆弱なシンボルがわかっているので、それをチェックします。現時点では未ストリップのバイナリですが、 シンボルテーブルを削除するためにストリップし、脆弱なシンボルが出力に残ることを証明します。
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, now strip it and repeat
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
次に、OpenShift ペイロードイメージに同梱されているバイナリを確認します。
イメージから /usr/bin を抽出します。--only-files は必須です。そうしないと oc image extract
が /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
このダイジェストでは、これは 4.21 の cluster-config-operator イメージです。
-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
どのバージョンの x/crypto に対してビルドされたかを確認します。
$ 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 はすべての修正バージョンより低いため、モジュールバージョンのスキャナーはこれを検出します。 次にシンボルチェックを適用します。GO-2026-5023 以外にも、v0.55.0 と v0.56.0 で修正された golang.org/x/crypto の脆弱性があるため、それらの脆弱なシンボルをすべて一度にチェックします。
GO-2026-5023 => ssh.NewServerConn GO-2026-6303 => ssh.NewServerConn 再び GO-2026-6354 => ssh.Dial ssh.NewClientConn ssh.NewControlClientConn ssh.NewServerConn GO-2026-6355 => ssh.Dial ssh.NewClientConn ssh.NewControlClientConn ssh.NewServerConn
tests-ext バイナリは gzip 圧縮されて同梱されているため、まず解凍して両方をチェックします。
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)'
出力なし、やった、脆弱性なし!grep が一致するシンボルが存在しないという退屈な理由で 無言になっていないことを確認します。
$ 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
つまり、x/crypto は実際にリンクされていますが、リンカーは x/crypto/ssh のすべてを削除しました。
なぜなら、何もそこに到達しないからです。
これは他のペイロードイメージでも再現可能なはずです。イメージごとの違いは、バイナリがどこにあり、
上記の -tests-ext.gz のように圧縮されているかどうかだけです。
*-tests-ext のようなテストバイナリは、どの実行パス上にもないにもかかわらず、イメージに同梱されています。
それらが x/crypto/ssh を引き込む場合(kubernetes の k8s-tests-ext は e2e SSH ヘルパーのために
ssh.NewClientConn をリンクしています)、それは依然として実行中のコンポーネントの実行パスから外れています。
いずれにせよ、テストバイナリはイメージを大きくし、イメージプルなどを遅くするため、
イメージから削除するよう取り組みます。
以下は、陽性テストケースのバイナリを作成する際に Claude によって生成されたもので、証明には不要ですが、 そのまま残してあります。
脆弱性が存在することを証明するには不要です。上記ですでにそれを示していますが、 これも自由に実行してみてください。
go run . -addr 127.0.0.1:2222 -user demo -password demo
次に、別のターミナルで:
ssh -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null [email protected]
パスワードは demo です。セッションは挨拶を表示し、入力をエコーバックします。
起動するたびに新しい ed25519 ホストキーが生成されるため、ディスクには何も書き込まれません。
v0.51.0 では、govulncheck は golang.org/x/crypto/ssh に到達可能な脆弱性を 10 件報告し、
すべて main.go → ssh.NewServerConn を通じてトレースされます
(GO-2026-5018 は ssh.NewSignerFromKey も通じてトレースされます)。
go get golang.org/x/[email protected]
go mod tidy
govulncheck ./...
v0.52.0 でそれらのほとんどは解消されますが、3件はより新しいリリースが必要です: GO-2026-6303 は v0.55.0 で修正され、GO-2026-6354 / GO-2026-6355 は v0.56.0 で修正されます。 v0.56.0 でスキャンするとクリーンになるはずです。