Kai Ole Hartwig — Blog
9 min read
High
By

CVE-2026-9804: KubeVirt `virt-exportserver` path traversal via symlink in exported PVCs — when the exporter pod itself is read

30 May 2026. On 28 May, Red Hat published CVE-2026-9804 (CVSS 7.7, HIGH; CWE-59 Improper Link Resolution Before File Access), a path traversal flaw in KubeVirt's virt-exportserver component. An attacker with namespace-level access can place a symlink in an exported filesystem PVC that points outside the intended mount root — on the next VMExport call the virt-exportserver reads the referenced files and returns them as part of the export. Affected are Red Hat OpenShift Virtualization 4 and Container Native Virtualization in the packages container-native-virtualization/virt-exportserver and container-native-virtualization/virt-exportserver-rhel9. For my customers with OpenShift Virtualization stacks the finding is operational — a small but existing class where virtualised workloads run in parallel with containerised ones on the same cluster.

AI-generated · gpt-image 2.0

TL;DR — the 90-second summary

What was published?

CVE-2026-9804 (Red Hat disclosure 28 May 2026, CVSS 7.7 HIGH, CWE-59 Improper Link Resolution Before File Access). Class: path traversal via symlink. Mechanism: the virt-exportserver component in KubeVirt serves the VMExport API — functionality that exports volumes of virtual machines out of a cluster. When exporting filesystem PVCs, the exporter walks the PVC mount root and reads the files. Until now the exporter followed symlinks without checking whether the symlink target stays inside the mount root — an attacker with write access to the PVC can place a symlink pointing to /etc/secrets/, /var/run/secrets/kubernetes.io/serviceaccount/token, or arbitrary other paths in the exporter pod filesystem.

How bad?

HIGH (CVSS 7.7). Reach: arbitrary file read from the exporter pod filesystem. What sits there depends on the pod configuration — on every KubeVirt exporter pod at least the service account token, the ConfigMap/Secret mounts of the component, and possibly container image internals are readable. The service account token is the operationally most important hit.

Which versions are affected?

Red Hat OpenShift Virtualization 4 and Container Native Virtualization in the packages container-native-virtualization/virt-exportserver and container-native-virtualization/virt-exportserver-rhel9. Upstream KubeVirt with active VMExport functionality is similarly affected.

Am I affected?

You are affected if your platform uses OpenShift Virtualization — that is, if your OpenShift cluster runs not only container workloads but also virtual machines via KubeVirt. This is a small but existing class in the German Mittelstand. If KubeVirt is installed and VMExport is actively used the flaw is operational — the precondition is a user with write access to the exported PVC.

Immediate mitigation?

Three steps. First, check whether KubeVirt is installed in the cluster (oc get csv -A | grep -i kubevirt) and whether VMExport resources exist (oc get virtualmachineexports -A). Second, if active: lift to the Red Hat OpenShift Virtualization patch level for CVE-2026-9804. Third, stopgap: reduce VMExport permissions to the minimum — only cluster-admin or explicitly named backup service accounts should have virtualmachineexports.export.kubevirt.io create permission.

Severity?

Hero badge high. Active exploitation as of 30 May is not publicly documented. Symlink-based path traversal classes have a standardised exploit track.

What happened

On 28 May 2026 Red Hat published a security advisory for the OpenShift Virtualization component virt-exportserver (part of the KubeVirt project in the Red Hat distribution) — CVE-2026-9804, CVSS 7.7 (HIGH), CWE-59 (Improper Link Resolution Before File Access). Red Hat credits Thai Son Dinh (VinSOC, GitHub @sondt99) for the finding.

KubeVirt is the container-native virtualisation project in the CNCF ecosystem — it allows defining virtual machines as Kubernetes custom resources and running them on a Kubernetes/OpenShift cluster, with the same RBAC, networking and storage patterns as container workloads. One of the standard functions is VMExport: via the VirtualMachineExport custom resource the volumes of a VM can be exported out of the cluster, for example for backup, migration to another platform, or off-cluster processing. The export is served by a dedicated pod (virt-exportserver) which mounts the PVC and streams its contents back to the caller via an HTTPS API.

The bug sits in the walk logic of the virt-exportserver for filesystem PVCs. When a PVC is exported in filesystem mode (as opposed to block mode, which streams raw bytes), the exporter iterates over the PVC file structure and reads the individual files. Until now the exporter followed symlinks in the PVC content without checking whether the symlink target lay inside the PVC mount root. An attacker with write access to the PVC can place a symlink that points, for example, to /var/run/secrets/kubernetes.io/serviceaccount/token — the service account token of the exporter pod in the cluster container filesystem. On export the symlink resolution is followed, the token is read and returned as part of the export stream.

The patch fixes the flaw through an explicit symlink-target check in the walk loop. Symlinks pointing outside the mount root are rejected; symlinks inside the root are followed as before.

Technical analysis

Structurally CVE-2026-9804 is a teaching case in the CWE-59 class — „Improper Link Resolution Before File Access“. This class is one of the oldest and most-recurring in the Unix/Linux filesystem security world: a program that works with filesystem paths does not check whether the resolved file lies inside the expected directory and follows symlinks blindly. The templates reach from classic /tmp race conditions through archive extraction bugs (tar/zip symlink classes since the 1990s) to more recent container runtime bugs.

The point with CVE-2026-9804 is the specific context: a pod in the cluster, running with the permissions of its service account, reads files that a pod-external attacker controls. If the exporter pod filesystem contains cluster tokens, mounted secrets or further sensitive material (which is the case on every standard Kubernetes pod — /var/run/secrets/kubernetes.io/serviceaccount/token is everywhere), this data flows back to the attacker via the export stream.

Methodologically important is the container-specific assessment. In classic, pod-less environments a CWE-59 flaw with „information disclosure from the server filesystem“ would be a serious but locally bounded class. In container environments the pod filesystem layer is a different reality: service account tokens, cluster secrets, container image internals, sometimes even mounted cloud credentials all sit on the same filesystem. The blast radius of a CWE-59 flaw in a pod is therefore often larger than a naive reading suggests.

The link to today's situation: CVE-2026-9804 sits in the same Red Hat drop block as CVE-2026-4408 Samba, CVE-2026-44604 rpmuncompress, CVE-2026-42965 + CVE-2026-46579 OpenShift Router and CVE-2026-9795 Keycloak FGAPv2 — six Red Hat component disclosures in 72 hours.

What this means for the Mittelstand

OpenShift Virtualization is a selectively deployed component in the German Mittelstand. It makes sense for customers who maintain two parallel workload classes — virtualised legacy applications (Windows server workloads, older Linux distributions, database VMs that cannot be containerised) and modern containerised workloads — and want to run both classes on a unified cluster infrastructure.

This class is not the Mittelstand default, but it exists — I operate some such setups. For these customers CVE-2026-9804 is operational.

The specific operational question is: who in your KubeVirt namespaces has write access to the VM PVCs? In single-tenant cluster setups (one customer org, all workloads belong to a single IT department) the entry bar is high — attackers must first enter the cluster before they can exploit the flaw. In multi-tenant setups the bar is lower.

On the compliance side the finding touches the standard axes. GDPR Art. 32 is concerned once the exporter service account token grants access to resources that hold personal data. NIS-2 Art. 21 demands concrete multi-tenant isolation discipline for the affected sectors — a flaw converting namespace write access into service-account-token theft is exactly the class that escalates here.

Operationally, the escalation axis is the important point. In a multi-tenant setup a compromised customer could grab the exporter service-account token via the VMExport class and then look into other customer namespaces via the cluster API.

What this means for technical development

Architecturally CVE-2026-9804 forces three disciplines.

First, pod filesystem inventory. What sits in the filesystem of your platform operations pods? Service account tokens (everywhere), cluster secrets (depending on mount configuration), cloud credentials (depending on service-mesh configuration), container image internals (depending on the image), custom mounts. An honest answer to this question per pod class is the foundation of any defence-in-depth posture against CWE-59 classes.

Second, service-account-token mount discipline. Kubernetes has allowed since version 1.6 the explicit configuration automountServiceAccountToken: false at pod and ServiceAccount level. This stops the service account token from being mounted into the pod. For pods that do not need cluster API access, automountServiceAccountToken: false is the clean default — and structurally rules out the whole class „CWE-59 → service account token theft“.

Third, tenant isolation in multi-tenant clusters. If you run several customers or departments on one cluster, you should operate separate service accounts per tenant for components that have cross-namespace permissions (KubeVirt VMExport is one such class) — not a single cluster-wide exporter service account.

Concrete recommendation

In this order. First, inventory today: per OpenShift cluster check whether KubeVirt is installed (oc get csv -A | grep -i kubevirt or oc get crd virtualmachines.kubevirt.io) and whether active VMExport resources exist (oc get virtualmachineexports -A). If not installed: no action needed. Second, if installed: lift to the Red Hat OpenShift Virtualization patch level for CVE-2026-9804 (via the OpenShift operator update path). Third, stopgap until the patch: reduce VMExport create permissions to the minimum — only explicitly named backup or cluster-admin service accounts should have create permission on virtualmachineexports.export.kubevirt.io. Fourth, pod filesystem audit: check in the virt-exportserver pod spec which secrets, ConfigMaps and volumes are mounted; identify sensitive mounts that are not needed for the export path and remove them. Fifth, service-account-token mount audit: in the ServiceAccount definition of the exporter and comparable platform operations pods check whether automountServiceAccountToken: false can be set without breaking functionality.

If these steps do not run from your own capacity, talk to me: I deliver OpenShift platforms in which KubeVirt operations, tenant isolation and pod filesystem hygiene sit as a continuous process.

This post reflects my technical and strategic assessment. It does not replace legal advice or a data protection impact assessment.

Sources

About the author

[Translate to English:] Foto von Kai Ole Hartwig.

Kai Ole Hartwig

Freelance DevSecOps consultant · OnlyOle Consulting

Programming since 2002 – self-taught, set up my own business with KO-Web in 2012. Over 100 projects, with a focus on security, performance, automation and quality. Today freelance: DevSecOps consulting, training and software development.