Cloud Security Wire
AWS Azure GCP RSS
AWSAzureGCP CVE Analysis medium

CVE-2026-3864 and CVE-2026-3865: Path Traversal in Kubernetes' NFS and SMB CSI Drivers

A pair of path traversal flaws in the community CSI drivers for NFS and SMB let anyone who can create a PersistentVolume delete or overwrite directories anywhere on the backing file server — including other tenants' data on EKS, AKS, and GKE clusters that share storage. Here's how the bug works and how to close it.

By Editorial Team · ·
#Kubernetes#CSI#NFS#SMB#CVE-2026-3864#CVE-2026-3865#path traversal#EKS#AKS#GKE#storage#cloud security

Two Kubernetes storage advisories landed earlier this year and quietly kept expanding: CVE-2026-3864 in kubernetes-csi/csi-driver-nfs and CVE-2026-3865 in kubernetes-csi/csi-driver-smb. Both are the same bug class in two drivers — insufficient validation of the subDir field embedded in a PersistentVolume’s volumeHandle, which lets an attacker who can create a PV walk out of the directory the driver is supposed to manage and operate on arbitrary paths on the backing NFS or SMB server. On a multi-tenant cluster, that arbitrary path can belong to a different team, a different namespace, or a different customer entirely.

Neither CVE is new in the news-cycle sense — NFS was disclosed in March 2026, SMB in April — but coverage of the mechanism, and of how it plays out on managed Kubernetes in AWS, Azure, and GCP, has been thin. It’s worth walking through because the driver pattern it exploits (dynamic subpath provisioning from PVC metadata) is extremely common and the fix requires an explicit upgrade — there’s no server-side patch here, unlike a hyperscaler-hosted control plane flaw.

How the drivers use subDir

Both csi-driver-nfs and csi-driver-smb support dynamic provisioning where each PersistentVolumeClaim gets its own subdirectory on a shared NFS export or SMB share, rather than a dedicated volume per claim. A typical StorageClass looks like this:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
  server: nfs-server.internal
  share: /export/k8s
  subDir: "${pvc.metadata.namespace}/${pvc.metadata.name}"
reclaimPolicy: Delete
mountOptions:
  - nfsvers=4.1

When a PVC is created, the driver substitutes the namespace and PVC name into subDir, then encodes the resolved path into the resulting PersistentVolume’s volumeHandle. That handle is what the driver reads back on mount, unmount, and — critically — on delete, when reclaimPolicy: Delete tells it to remove the subdirectory entirely.

Where the validation gap sits

The flaw is that subDir values embedded in a volumeHandle were not checked for traversal sequences before being joined onto the export’s base path. If an actor can create a PersistentVolume directly (rather than only a PVC that goes through StorageClass templating), they can hand-craft a volumeHandle containing a subDir like ../../other-namespace/other-pvc or ../../../etc. The driver dutifully joins that path to the export root and, on cleanup, deletes whatever is there.

This requires the ability to create PersistentVolume objects — cluster-scoped resources — which normally means cluster-admin or an equivalent broad RBAC grant. That access requirement is why both CVEs score Medium (CVSS 3.1, 6.5) rather than Critical: AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:H. Privileges Required is High. But “requires elevated privilege” is a weaker bar than it sounds in real clusters. Platform teams, CI/CD service accounts with cluster-admin-scoped kubeconfigs, GitOps controllers like Argo CD syncing manifests from a shared repo, and any operator with cluster-admin for legitimate reasons are all in a position to trigger this — intentionally or via a compromised credential, a malicious dependency in a manifest pipeline, or a supply-chain-poisoned Helm chart that slips a crafted PV into a release.

The consequence isn’t disclosure — Confidentiality impact is None in the CVSS vector — it’s Integrity and Availability: unauthorized deletion or modification of files outside the intended managed path. On a shared NFS export backing multiple tenants’ PVCs, that means one tenant’s crafted volume handle can delete another tenant’s data.

Why this matters more on managed Kubernetes

EKS, AKS, and GKE don’t ship these CSI drivers by default, but they’re extremely common additions wherever teams need ReadWriteMany volumes — shared model artifact stores, CI build caches, legacy application migrations that expect a POSIX filesystem. Because the drivers are installed as regular cluster add-ons (often via Helm, sometimes bundled into a platform team’s base cluster image), version drift is easy: a cluster provisioned in 2025 and left alone will still be running the vulnerable driver version today, with nobody auditing it because “CSI driver” doesn’t show up on the checklist the way “control plane version” does.

Checking exposure

Confirm which driver version is deployed and audit existing PVs for suspicious volumeHandle values:

# Check the driver image tag in the deployed daemonset/deployment
kubectl get pods -n kube-system -l app=csi-nfs-controller -o jsonpath='{.items[*].spec.containers[*].image}'
kubectl get pods -n kube-system -l app=csi-smb-controller -o jsonpath='{.items[*].spec.containers[*].image}'

# Look for path traversal sequences in existing PersistentVolumes
kubectl get pv -o json | jq -r '.items[] | select(.spec.csi.driver=="nfs.csi.k8s.io" or .spec.csi.driver=="smb.csi.k8s.io") | .spec.csi.volumeHandle' | grep -E '\.\./|/\.\.'

# List who currently holds PV create permission cluster-wide
kubectl get clusterrolebindings -o json | jq -r '.items[] | select(.roleRef.name=="cluster-admin") | .subjects[]?.name'

Remediation

  • Upgrade the drivers. csi-driver-nfs to v4.13.1 or later, csi-driver-smb to v1.20.1 or later. Both fixes add path containment validation on the subDir field before it’s joined to the export root.
  • Restrict PersistentVolume creation. Static PV creation is a cluster-admin-tier operation for a reason. Scope any automation, CI pipeline, or GitOps controller that touches PVs to the narrowest RBAC role that still functions — a namespaced role bound to PVC creation, with dynamic provisioning handling PV creation on the controller’s behalf, rather than a broad grant that also permits direct PV authoring.
  • Segment shared exports by tenant. Where possible, back different tenants or environments with separate NFS exports or SMB shares rather than one shared export differentiated only by subDir path. A traversal bug in the provisioning path is far less damaging if there’s nothing sensitive to traverse into.
  • Alert on reclaimPolicy: Delete for shared-storage StorageClasses. Deletion is where the traversal bug does its damage. Consider Retain for any StorageClass backing multi-tenant NFS/SMB, with a separate, audited cleanup process instead of driver-triggered deletion.
  • Pin and scan CSI driver versions like any other supply-chain dependency. If your Helm chart or platform image references a driver by a floating tag, pin it and add it to whatever CVE-scanning pipeline already covers your container base images — CSI add-ons tend to fall outside that scope by default.

The bigger lesson generalizes past these two CVEs: any controller that resolves a user-influenced path (PVC name, namespace, subDir template) into a filesystem operation on shared backend storage is a path traversal candidate. If you run other CSI drivers with similar subDir-style templating — for Ceph, GlusterFS, or vendor-specific NFS gateways — the same class of check is worth confirming exists before you trust dynamic provisioning against a shared export in production.

← All Analysis Subscribe via RSS