Safeguard
Vulnerability Analysis

Kubernetes validating admission webhook bypass (CVE-2021-25735)

CVE-2021-25735 let attackers bypass Kubernetes validating admission webhooks on Node objects via a kube-apiserver flaw. Here's the fix and detection path.

Vikram Iyer
Cloud Security Engineer
7 min read

Kubernetes clusters that rely on validating admission webhooks to enforce security policy on Node objects were exposed to a quiet but consequential bypass: CVE-2021-25735. The flaw lived in kube-apiserver's node update path, where the server could substitute part of the incoming node's spec over the old object's spec before handing the request to a validating admission webhook — meaning the webhook evaluated a version of the object that didn't match what was actually persisted. For any cluster using webhooks that make allow/deny decisions by comparing the old and new state of a Node (for example, rejecting changes to taints, labels used for scheduling isolation, or unschedulable status), an attacker with node-update permissions could slip unauthorized changes past the policy engine entirely. The admission control layer wasn't just misconfigured — it was structurally blind to the real diff it was supposed to be judging.

What Went Wrong, Technically

Kubernetes admission webhooks are supposed to receive both the oldObject and the proposed object in an AdmissionReview request, so a policy can compare before-and-after state and reject changes that violate a rule (e.g., "no one may remove the dedicated=payments taint from this node"). The bug in affected kube-apiserver versions caused parts of node.Spec from the incoming request to overwrite the corresponding fields of oldNode.Spec before the admission chain ran its validation step. In practice, this meant a webhook configured to deny a request based on the previous value of a field could be tricked: an attacker submits a patch that changes the field they want to smuggle through, while the apiserver's internal handling causes the webhook to see an old-object view that already reflects (or partially reflects) the new state — collapsing the diff the webhook depends on to reach its decision. The result is a validating webhook that appears to be running, appears to be evaluating the request, and still returns "allow" for a change it was explicitly built to block.

Two things made this particularly notable rather than purely academic. First, it targeted Node objects specifically — a resource type with outsized blast radius in multi-tenant clusters, since node metadata frequently gates scheduling decisions, taint-based isolation, and node-level trust boundaries. Second, it didn't require any webhook misconfiguration on the defender's part; a correctly written webhook policy could still be bypassed purely because of how kube-apiserver assembled the objects it sent for evaluation. That distinction matters for triage: this isn't a "fix your webhook rules" issue, it's a "the control plane itself needs patching" issue.

Affected Versions and Components

  • Component: kube-apiserver (the vulnerability lives in the admission-review construction logic for node updates; it does not affect kubelet's own use of the built-in NodeRestriction admission plugin).
  • Affected versions:
    • kube-apiserver v1.20.0 – v1.20.5
    • kube-apiserver v1.19.0 – v1.19.9
    • kube-apiserver v1.18.17 and earlier
  • Fixed versions: v1.21.0, v1.20.6, v1.19.10, and v1.18.18.
  • Who is actually exposed: clusters running a validating admission webhook configured for Node objects that makes decisions based at least partly on the old value of a field. Clusters that don't run any custom validating webhooks against nodes, or whose node webhooks only inspect the new object's absolute values (not diffs against the old state), are not meaningfully impacted by this specific bypass path.

Because the flaw sits in the control plane, every managed Kubernetes offering built on an affected upstream version (EKS, GKE, AKS, and self-managed distributions alike) needed a control-plane patch or version bump — this wasn't something workload owners could remediate from inside a namespace.

CVSS, EPSS, and KEV Context

CVE-2021-25735 carries a CVSS 3.1 base score of 6.5 (Medium), with a vector of AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:H. The score reflects network attack vector and low attack complexity, offset by the requirement for high-privilege credentials (node-update permission is not something a typical workload identity holds) and no user interaction, with high impact to integrity and availability once exploited — consistent with an attacker being able to force through unauthorized node-level changes.

The vulnerability does not appear in CISA's Known Exploited Vulnerabilities (KEV) catalog, and its EPSS score sits well below the threshold associated with active mass exploitation — there are no public reports of this bypass being used in the wild. That combination (Medium CVSS, no KEV listing, low EPSS) is exactly the profile that causes vulnerabilities to get deprioritized in a raw severity-sorted backlog, which is the wrong instinct here: the practical risk is entirely a function of whether your cluster has RBAC that grants node-update rights broadly and whether your webhooks lean on old-object comparisons — context a CVSS score alone can't capture.

Disclosure Timeline

  • Discovery/report: The issue was identified and reported to the Kubernetes security team by Rogerio Bastos and Ari Lima of Red Hat.
  • Public tracking issue opened: March 10, 2021, as GitHub issue kubernetes/kubernetes#100096, alongside the coordinated security advisory.
  • Patches merged: Fixes landed via PR #99946 (targeting v1.21.0), PR #100315 (v1.20.6), PR #100316 (v1.19.10), and PR #100317 (v1.18.18).
  • Coordinated disclosure: Announced through the kubernetes-security-announce mailing list alongside the related CVE-2021-25735 through CVE-2021-25741 batch of April 2021 Kubernetes security fixes, giving distributions and cloud providers lead time to backport before public detail was widely circulated.
  • Downstream response: Managed Kubernetes providers (AKS, EKS, GKE) and OS/package distributions (Red Hat, Alpine, etc.) shipped control-plane patches and advisories in the following weeks, and independent researchers (Sysdig, Cloud Security Alliance) later published exploitation walkthroughs and detection guidance once the fix had propagated.

Remediation Steps

  1. Patch or upgrade kube-apiserver first. This is a control-plane bug, not a workload bug — confirm your cluster (or your managed Kubernetes provider) is running kube-apiserver >= v1.21.0, >= v1.20.6, >= v1.19.10, or >= v1.18.18. For managed services, check the provider's Kubernetes version release notes for the specific patch build that backports this fix.
  2. Inventory every validating (and mutating) admission webhook scoped to Node objects. Identify which ones make decisions by diffing oldObject against the incoming object rather than validating the new object's fields in isolation — those are the ones this bug could have bypassed.
  3. Audit RBAC for node update/patch permissions. Confirm which service accounts, users, and groups hold update or patch verbs on the nodes resource (and nodes/status). This should be a short, deliberate list — not a byproduct of an overly broad ClusterRole.
  4. Re-test your node admission policies post-patch. After upgrading, replay the specific change scenarios your webhooks are meant to block (taint removal, unschedulable flips, label changes tied to isolation) and confirm they're actually rejected now that the apiserver sends a correct before/after diff.
  5. Turn on and review Kubernetes audit logs for node update events retroactively, looking for node spec changes that don't correlate with expected automation (cluster autoscaler, node lifecycle controllers) — a compensating control while patches roll out, and a forensic trail if you suspect prior exploitation.
  6. Track this as part of routine Kubernetes version hygiene, not a one-off fire drill. CVE-2021-25735 was one of a cluster of node-object and admission-related CVEs (2021-25736, 2021-25737, 2021-25741) fixed in the same release wave — clusters lagging on one are usually lagging on all of them.

How Safeguard Helps

Vulnerabilities like CVE-2021-25735 are exactly where CVSS-only prioritization breaks down: the score says "Medium," but whether it's a live risk in your environment depends entirely on your specific RBAC grants and webhook logic. Safeguard's reachability analysis inspects your actual cluster configuration and admission policy graph to tell you whether any node-scoped validating webhook in your environment relies on old-object comparisons — turning an abstract CVE into a concrete yes/no answer for your infrastructure. Griffin AI correlates your kube-apiserver version, RBAC bindings, and webhook configurations against the vulnerable code paths to surface this class of control-plane bypass before an attacker does, rather than after an audit-log review turns up something suspicious. Safeguard's SBOM generation and ingest pipeline tracks control-plane component versions across every cluster in your fleet — including managed Kubernetes offerings — so you always know precisely which clusters still run a pre-patch kube-apiserver, without manually cross-referencing provider release notes. And where a version bump or Helm chart pin is the fix, Safeguard opens an auto-fix pull request against the relevant infrastructure-as-code repository, so remediation ships as a reviewable change instead of a manual, cluster-by-cluster scramble.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.