Medium severity6.7GHSA Advisory· Published Aug 27, 2025· Updated Apr 15, 2026
CVE-2025-5187
CVE-2025-5187
Description
A vulnerability exists in the NodeRestriction admission controller in Kubernetes clusters where node users can delete their corresponding node object by patching themselves with an OwnerReference to a cluster-scoped resource. If the OwnerReference resource does not exist or is subsequently deleted, the given node object will be deleted via garbage collection.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
k8s.io/kubernetesGo | < 1.31.12 | 1.31.12 |
k8s.io/kubernetesGo | >= 1.32.0-alpha.0, < 1.32.8 | 1.32.8 |
k8s.io/kubernetesGo | >= 1.33.0-alpha.0, < 1.33.4 | 1.33.4 |
Affected products
1- Range: >= 1.33.0-alpha.0, < 1.33.4
Patches
1a2d98cac56a0Merge pull request #133470 from natherz97/node-deletion-release-1.31
2 files changed · +35 −6
plugin/pkg/admission/noderestriction/admission.go+5 −0 modified@@ -489,6 +489,11 @@ func (p *Plugin) admitNode(nodeName string, a admission.Attributes) error { return admission.NewForbidden(a, fmt.Errorf("node %q is not allowed to modify taints", nodeName)) } + // Don't allow a node to update its own ownerReferences. + if !apiequality.Semantic.DeepEqual(node.OwnerReferences, oldNode.OwnerReferences) { + return admission.NewForbidden(a, fmt.Errorf("node %q is not allowed to modify ownerReferences", nodeName)) + } + // Don't allow a node to update labels outside the allowed set. // This would allow a node to add or modify its labels in a way that would let it steer privileged workloads to itself. modifiedLabels := getModifiedLabels(node.Labels, oldNode.Labels)
plugin/pkg/admission/noderestriction/admission_test.go+30 −6 modified@@ -247,10 +247,14 @@ func (a *admitTestCase) run(t *testing.T) { func Test_nodePlugin_Admit(t *testing.T) { var ( - mynode = &user.DefaultInfo{Name: "system:node:mynode", Groups: []string{"system:nodes"}} - bob = &user.DefaultInfo{Name: "bob"} + trueRef = true + mynode = &user.DefaultInfo{Name: "system:node:mynode", Groups: []string{"system:nodes"}} + bob = &user.DefaultInfo{Name: "bob"} + + mynodeObjMeta = metav1.ObjectMeta{Name: "mynode", UID: "mynode-uid"} + mynodeObjMetaOwnerRefA = metav1.ObjectMeta{Name: "mynode", UID: "mynode-uid", OwnerReferences: []metav1.OwnerReference{{Name: "fooerA", Controller: &trueRef}}} + mynodeObjMetaOwnerRefB = metav1.ObjectMeta{Name: "mynode", UID: "mynode-uid", OwnerReferences: []metav1.OwnerReference{{Name: "fooerB", Controller: &trueRef}}} - mynodeObjMeta = metav1.ObjectMeta{Name: "mynode", UID: "mynode-uid"} mynodeObj = &api.Node{ObjectMeta: mynodeObjMeta} mynodeObjConfigA = &api.Node{ObjectMeta: mynodeObjMeta, Spec: api.NodeSpec{ConfigSource: &api.NodeConfigSource{ ConfigMap: &api.ConfigMapNodeConfigSource{ @@ -267,9 +271,11 @@ func Test_nodePlugin_Admit(t *testing.T) { KubeletConfigKey: "kubelet", }}}} - mynodeObjTaintA = &api.Node{ObjectMeta: mynodeObjMeta, Spec: api.NodeSpec{Taints: []api.Taint{{Key: "mykey", Value: "A"}}}} - mynodeObjTaintB = &api.Node{ObjectMeta: mynodeObjMeta, Spec: api.NodeSpec{Taints: []api.Taint{{Key: "mykey", Value: "B"}}}} - othernodeObj = &api.Node{ObjectMeta: metav1.ObjectMeta{Name: "othernode"}} + mynodeObjTaintA = &api.Node{ObjectMeta: mynodeObjMeta, Spec: api.NodeSpec{Taints: []api.Taint{{Key: "mykey", Value: "A"}}}} + mynodeObjTaintB = &api.Node{ObjectMeta: mynodeObjMeta, Spec: api.NodeSpec{Taints: []api.Taint{{Key: "mykey", Value: "B"}}}} + mynodeObjOwnerRefA = &api.Node{ObjectMeta: mynodeObjMetaOwnerRefA} + mynodeObjOwnerRefB = &api.Node{ObjectMeta: mynodeObjMetaOwnerRefB} + othernodeObj = &api.Node{ObjectMeta: metav1.ObjectMeta{Name: "othernode"}} coremymirrorpod, v1mymirrorpod = makeTestPod("ns", "mymirrorpod", "mynode", true) coreothermirrorpod, v1othermirrorpod = makeTestPod("ns", "othermirrorpod", "othernode", true) @@ -1052,6 +1058,24 @@ func Test_nodePlugin_Admit(t *testing.T) { attributes: admission.NewAttributesRecord(setForbiddenUpdateLabels(mynodeObj, "new"), setForbiddenUpdateLabels(mynodeObj, "old"), nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, &metav1.UpdateOptions{}, false, mynode), err: `is not allowed to modify labels: foo.node-restriction.kubernetes.io/foo, node-restriction.kubernetes.io/foo, other.k8s.io/foo, other.kubernetes.io/foo`, }, + { + name: "forbid update of my node: add owner reference", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(mynodeObjOwnerRefA, mynodeObj, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, &metav1.UpdateOptions{}, false, mynode), + err: "node \"mynode\" is not allowed to modify ownerReferences", + }, + { + name: "forbid update of my node: remove owner reference", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(mynodeObj, mynodeObjOwnerRefA, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, &metav1.UpdateOptions{}, false, mynode), + err: "node \"mynode\" is not allowed to modify ownerReferences", + }, + { + name: "forbid update of my node: change owner reference", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(mynodeObjOwnerRefA, mynodeObjOwnerRefB, nodeKind, mynodeObj.Namespace, mynodeObj.Name, nodeResource, "", admission.Update, &metav1.UpdateOptions{}, false, mynode), + err: "node \"mynode\" is not allowed to modify ownerReferences", + }, // Other node object {
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
5- github.com/advisories/GHSA-4x4m-3c2p-qppcghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-5187ghsaADVISORY
- github.com/kubernetes/kubernetes/commit/a2d98cac56a0c5cb2d8abc4d087fc00846b3bc0fghsaWEB
- github.com/kubernetes/kubernetes/issues/133471nvdWEB
- groups.google.com/g/kubernetes-security-announce/c/znSNY7XCztEnvdWEB
News mentions
0No linked articles in our index yet.