KubeVirt Improper TLS Certificate Management Handling Allows API Identity Spoofing
Description
KubeVirt is a virtual machine management add-on for Kubernetes. Prior to 1.5.3 and 1.6.1, due to the peer verification logic in virt-handler (via verifyPeerCert), an attacker who compromises a virt-handler instance, could exploit these shared credentials to impersonate virt-api and execute privileged operations against other virt-handler instances potentially compromising the integrity and availability of the VM managed by it. This vulnerability is fixed in 1.5.3 and 1.6.1.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
kubevirt.io/kubevirtGo | < 1.5.3 | 1.5.3 |
kubevirt.io/kubevirtGo | >= 1.6.0-alpha.0, < 1.6.1 | 1.6.1 |
Affected products
1Patches
3b9773bc588e6SetupTLSWithCertManager now enforces CN
3 files changed · +55 −4
pkg/util/tls/tls.go+29 −1 modified@@ -17,6 +17,7 @@ import ( ) const noSrvCertMessage = "No server certificate, server is not yet ready to receive traffic" +const serverNotReadyMsg = "Server is not yet ready to receive traffic" var ( cipherSuites = tls.CipherSuites() @@ -91,7 +92,7 @@ func SetupExportProxyTLS(certManager certificate.Manager, kubeVirtStore cache.St return tlsConfig } -func SetupTLSWithCertManager(caManager ClientCAManager, certManager certificate.Manager, clientAuth tls.ClientAuthType, clusterConfig *virtconfig.ClusterConfig) *tls.Config { +func SetupTLSWithCertManager(caManager KubernetesCAManager, certManager certificate.Manager, clientAuth tls.ClientAuthType, clusterConfig *virtconfig.ClusterConfig) *tls.Config { tlsConfig := &tls.Config{ GetCertificate: func(info *tls.ClientHelloInfo) (certificate *tls.Certificate, err error) { cert := certManager.Current() @@ -122,6 +123,33 @@ func SetupTLSWithCertManager(caManager ClientCAManager, certManager certificate. Certificates: []tls.Certificate{*cert}, ClientCAs: clientCAPool, ClientAuth: clientAuth, + VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + if len(verifiedChains) == 0 || len(verifiedChains[0]) == 0 { + return nil + } + + certificate, err := x509.ParseCertificate(rawCerts[0]) + if err != nil { + return fmt.Errorf("failed to parse peer certificate: %v", err) + } + + CNs, err := caManager.GetCNs() + if err != nil { + log.Log.Reason(err).Error(serverNotReadyMsg) + return fmt.Errorf(serverNotReadyMsg) + } + + if len(CNs) == 0 { + return nil + } + for _, CN := range CNs { + if certificate.Subject.CommonName == CN { + return nil + } + } + + return fmt.Errorf("Common name is invalid") + }, } config.BuildNameToCertificate()
pkg/util/tls/tls_test.go+25 −2 modified@@ -31,6 +31,7 @@ import ( type mockCAManager struct { caBundle []byte + cns []string } type mockCertManager struct { @@ -66,9 +67,13 @@ func (m *mockCAManager) GetCurrentRaw() ([]byte, error) { return nil, fmt.Errorf("not implemented") } +func (m *mockCAManager) GetCNs() ([]string, error) { + return m.cns, nil +} + var _ = Describe("TLS", func() { - var caManager kvtls.ClientCAManager + var caManager kvtls.KubernetesCAManager var certmanagers map[string]certificate.Manager var clusterConfig *virtconfig.ClusterConfig var kubeVirtStore cache.Store @@ -220,7 +225,8 @@ var _ = Describe("TLS", func() { }), ) - DescribeTable("should verify self-signed client and server certificates", func(serverSecret, clientSecret string, errStr string) { + DescribeTable("should verify self-signed client and server certificates", func(serverSecret, clientSecret, errStr string, cns []string) { + caManager.(*mockCAManager).cns = cns serverTLSConfig := kvtls.SetupTLSWithCertManager(caManager, certmanagers[serverSecret], tls.RequireAndVerifyClientCert, clusterConfig) clientTLSConfig := kvtls.SetupTLSForVirtHandlerClients(caManager, certmanagers[clientSecret], false) srv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -248,18 +254,35 @@ var _ = Describe("TLS", func() { components.VirtHandlerServerCertSecretName, components.VirtHandlerCertSecretName, "", + []string{"kubevirt.io:system:client:virt-handler"}, + ), + Entry( + "connect with proper certificates with no CN auth", + components.VirtHandlerServerCertSecretName, + components.VirtHandlerCertSecretName, + "", + []string{}, + ), + Entry( + "fail if client uses an invalid certificates (CN)", + components.VirtHandlerServerCertSecretName, + components.VirtHandlerCertSecretName, + "remote error: tls: bad certificate", + []string{"kubevirt.io:system:clientv2:virt-handler"}, ), Entry( "fail if client uses an invalid certificate", components.VirtHandlerServerCertSecretName, components.VirtHandlerServerCertSecretName, "remote error: tls: bad certificate", + []string{"kubevirt.io:system:client:virt-handler"}, ), Entry( "fail if server uses an invalid certificate", components.VirtHandlerCertSecretName, components.VirtHandlerCertSecretName, "x509: certificate specifies an incompatible key usage", + []string{"kubevirt.io:system:client:virt-handler"}, ), )
pkg/virt-api/api.go+1 −1 modified@@ -960,7 +960,7 @@ func (app *virtAPIApp) registerMutatingWebhook(informers *webhooks.Informers) { }) } -func (app *virtAPIApp) setupTLS(k8sCAManager kvtls.ClientCAManager, kubevirtCAManager kvtls.ClientCAManager) { +func (app *virtAPIApp) setupTLS(k8sCAManager kvtls.KubernetesCAManager, kubevirtCAManager kvtls.ClientCAManager) { // A VerifyClientCertIfGiven request means we're not guaranteed // a client has been authenticated unless they provide a peer
231dc69723f3SetupTLSWithCertManager now enforces CN
3 files changed · +55 −4
pkg/util/tls/tls.go+29 −1 modified@@ -17,6 +17,7 @@ import ( ) const noSrvCertMessage = "No server certificate, server is not yet ready to receive traffic" +const serverNotReadyMsg = "Server is not yet ready to receive traffic" var ( cipherSuites = tls.CipherSuites() @@ -91,7 +92,7 @@ func SetupExportProxyTLS(certManager certificate.Manager, kubeVirtStore cache.St return tlsConfig } -func SetupTLSWithCertManager(caManager ClientCAManager, certManager certificate.Manager, clientAuth tls.ClientAuthType, clusterConfig *virtconfig.ClusterConfig) *tls.Config { +func SetupTLSWithCertManager(caManager KubernetesCAManager, certManager certificate.Manager, clientAuth tls.ClientAuthType, clusterConfig *virtconfig.ClusterConfig) *tls.Config { tlsConfig := &tls.Config{ GetCertificate: func(info *tls.ClientHelloInfo) (certificate *tls.Certificate, err error) { cert := certManager.Current() @@ -122,6 +123,33 @@ func SetupTLSWithCertManager(caManager ClientCAManager, certManager certificate. Certificates: []tls.Certificate{*cert}, ClientCAs: clientCAPool, ClientAuth: clientAuth, + VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + if len(verifiedChains) == 0 || len(verifiedChains[0]) == 0 { + return nil + } + + certificate, err := x509.ParseCertificate(rawCerts[0]) + if err != nil { + return fmt.Errorf("failed to parse peer certificate: %v", err) + } + + CNs, err := caManager.GetCNs() + if err != nil { + log.Log.Reason(err).Error(serverNotReadyMsg) + return fmt.Errorf(serverNotReadyMsg) + } + + if len(CNs) == 0 { + return nil + } + for _, CN := range CNs { + if certificate.Subject.CommonName == CN { + return nil + } + } + + return fmt.Errorf("Common name is invalid") + }, } config.BuildNameToCertificate()
pkg/util/tls/tls_test.go+25 −2 modified@@ -31,6 +31,7 @@ import ( type mockCAManager struct { caBundle []byte + cns []string } type mockCertManager struct { @@ -66,9 +67,13 @@ func (m *mockCAManager) GetCurrentRaw() ([]byte, error) { return nil, fmt.Errorf("not implemented") } +func (m *mockCAManager) GetCNs() ([]string, error) { + return m.cns, nil +} + var _ = Describe("TLS", func() { - var caManager kvtls.ClientCAManager + var caManager kvtls.KubernetesCAManager var certmanagers map[string]certificate.Manager var clusterConfig *virtconfig.ClusterConfig var kubeVirtStore cache.Store @@ -220,7 +225,8 @@ var _ = Describe("TLS", func() { }), ) - DescribeTable("should verify self-signed client and server certificates", func(serverSecret, clientSecret string, errStr string) { + DescribeTable("should verify self-signed client and server certificates", func(serverSecret, clientSecret, errStr string, cns []string) { + caManager.(*mockCAManager).cns = cns serverTLSConfig := kvtls.SetupTLSWithCertManager(caManager, certmanagers[serverSecret], tls.RequireAndVerifyClientCert, clusterConfig) clientTLSConfig := kvtls.SetupTLSForVirtHandlerClients(caManager, certmanagers[clientSecret], false) srv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -248,18 +254,35 @@ var _ = Describe("TLS", func() { components.VirtHandlerServerCertSecretName, components.VirtHandlerCertSecretName, "", + []string{"kubevirt.io:system:client:virt-handler"}, + ), + Entry( + "connect with proper certificates with no CN auth", + components.VirtHandlerServerCertSecretName, + components.VirtHandlerCertSecretName, + "", + []string{}, + ), + Entry( + "fail if client uses an invalid certificates (CN)", + components.VirtHandlerServerCertSecretName, + components.VirtHandlerCertSecretName, + "remote error: tls: bad certificate", + []string{"kubevirt.io:system:clientv2:virt-handler"}, ), Entry( "fail if client uses an invalid certificate", components.VirtHandlerServerCertSecretName, components.VirtHandlerServerCertSecretName, "remote error: tls: bad certificate", + []string{"kubevirt.io:system:client:virt-handler"}, ), Entry( "fail if server uses an invalid certificate", components.VirtHandlerCertSecretName, components.VirtHandlerCertSecretName, "x509: certificate specifies an incompatible key usage", + []string{"kubevirt.io:system:client:virt-handler"}, ), )
pkg/virt-api/api.go+1 −1 modified@@ -990,7 +990,7 @@ func (app *virtAPIApp) registerMutatingWebhook(informers *webhooks.Informers) { }) } -func (app *virtAPIApp) setupTLS(k8sCAManager kvtls.ClientCAManager, kubevirtCAManager kvtls.ClientCAManager) { +func (app *virtAPIApp) setupTLS(k8sCAManager kvtls.KubernetesCAManager, kubevirtCAManager kvtls.ClientCAManager) { // A VerifyClientCertIfGiven request means we're not guaranteed // a client has been authenticated unless they provide a peer
af2f08a9a186SetupTLSWithCertManager now enforces CN
3 files changed · +55 −4
pkg/util/tls/tls.go+29 −1 modified@@ -17,6 +17,7 @@ import ( ) const noSrvCertMessage = "No server certificate, server is not yet ready to receive traffic" +const serverNotReadyMsg = "Server is not yet ready to receive traffic" var ( cipherSuites = tls.CipherSuites() @@ -91,7 +92,7 @@ func SetupExportProxyTLS(certManager certificate.Manager, kubeVirtStore cache.St return tlsConfig } -func SetupTLSWithCertManager(caManager ClientCAManager, certManager certificate.Manager, clientAuth tls.ClientAuthType, clusterConfig *virtconfig.ClusterConfig) *tls.Config { +func SetupTLSWithCertManager(caManager KubernetesCAManager, certManager certificate.Manager, clientAuth tls.ClientAuthType, clusterConfig *virtconfig.ClusterConfig) *tls.Config { tlsConfig := &tls.Config{ GetCertificate: func(info *tls.ClientHelloInfo) (certificate *tls.Certificate, err error) { cert := certManager.Current() @@ -122,6 +123,33 @@ func SetupTLSWithCertManager(caManager ClientCAManager, certManager certificate. Certificates: []tls.Certificate{*cert}, ClientCAs: clientCAPool, ClientAuth: clientAuth, + VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + if len(verifiedChains) == 0 || len(verifiedChains[0]) == 0 { + return nil + } + + certificate, err := x509.ParseCertificate(rawCerts[0]) + if err != nil { + return fmt.Errorf("failed to parse peer certificate: %v", err) + } + + CNs, err := caManager.GetCNs() + if err != nil { + log.Log.Reason(err).Error(serverNotReadyMsg) + return fmt.Errorf(serverNotReadyMsg) + } + + if len(CNs) == 0 { + return nil + } + for _, CN := range CNs { + if certificate.Subject.CommonName == CN { + return nil + } + } + + return fmt.Errorf("Common name is invalid") + }, } config.BuildNameToCertificate()
pkg/util/tls/tls_test.go+25 −2 modified@@ -31,6 +31,7 @@ import ( type mockCAManager struct { caBundle []byte + cns []string } type mockCertManager struct { @@ -66,9 +67,13 @@ func (m *mockCAManager) GetCurrentRaw() ([]byte, error) { return nil, fmt.Errorf("not implemented") } +func (m *mockCAManager) GetCNs() ([]string, error) { + return m.cns, nil +} + var _ = Describe("TLS", func() { - var caManager kvtls.ClientCAManager + var caManager kvtls.KubernetesCAManager var certmanagers map[string]certificate.Manager var clusterConfig *virtconfig.ClusterConfig var kubeVirtStore cache.Store @@ -220,7 +225,8 @@ var _ = Describe("TLS", func() { }), ) - DescribeTable("should verify self-signed client and server certificates", func(serverSecret, clientSecret string, errStr string) { + DescribeTable("should verify self-signed client and server certificates", func(serverSecret, clientSecret, errStr string, cns []string) { + caManager.(*mockCAManager).cns = cns serverTLSConfig := kvtls.SetupTLSWithCertManager(caManager, certmanagers[serverSecret], tls.RequireAndVerifyClientCert, clusterConfig) clientTLSConfig := kvtls.SetupTLSForVirtHandlerClients(caManager, certmanagers[clientSecret], false) srv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -248,18 +254,35 @@ var _ = Describe("TLS", func() { components.VirtHandlerServerCertSecretName, components.VirtHandlerCertSecretName, "", + []string{"kubevirt.io:system:client:virt-handler"}, + ), + Entry( + "connect with proper certificates with no CN auth", + components.VirtHandlerServerCertSecretName, + components.VirtHandlerCertSecretName, + "", + []string{}, + ), + Entry( + "fail if client uses an invalid certificates (CN)", + components.VirtHandlerServerCertSecretName, + components.VirtHandlerCertSecretName, + "remote error: tls: bad certificate", + []string{"kubevirt.io:system:clientv2:virt-handler"}, ), Entry( "fail if client uses an invalid certificate", components.VirtHandlerServerCertSecretName, components.VirtHandlerServerCertSecretName, "remote error: tls: bad certificate", + []string{"kubevirt.io:system:client:virt-handler"}, ), Entry( "fail if server uses an invalid certificate", components.VirtHandlerCertSecretName, components.VirtHandlerCertSecretName, "x509: certificate specifies an incompatible key usage", + []string{"kubevirt.io:system:client:virt-handler"}, ), )
pkg/virt-api/api.go+1 −1 modified@@ -990,7 +990,7 @@ func (app *virtAPIApp) registerMutatingWebhook(informers *webhooks.Informers) { }) } -func (app *virtAPIApp) setupTLS(k8sCAManager kvtls.ClientCAManager, kubevirtCAManager kvtls.ClientCAManager) { +func (app *virtAPIApp) setupTLS(k8sCAManager kvtls.KubernetesCAManager, kubevirtCAManager kvtls.ClientCAManager) { // A VerifyClientCertIfGiven request means we're not guaranteed // a client has been authenticated unless they provide a peer
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-ggp9-c99x-54gpghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-64434ghsaADVISORY
- github.com/kubevirt/kubevirt/commit/231dc69723f331dc02f65a31ab4c3d6869f40d6aghsax_refsource_MISCWEB
- github.com/kubevirt/kubevirt/commit/af2f08a9a186eccc650f87c30ab3e07b669e8b5bghsax_refsource_MISCWEB
- github.com/kubevirt/kubevirt/commit/b9773bc588e6e18ece896a2dad5336ef7a653074ghsax_refsource_MISCWEB
- github.com/kubevirt/kubevirt/security/advisories/GHSA-ggp9-c99x-54gpghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.