Every patch workflow starts from the same assumption: the CVE record tells the truth about which versions are fixed. On June 1, 2026, the Kubernetes Security Response Committee confirmed that assumption had been wrong for years on four CVEs — three records carried fixed version fields for vulnerabilities that were never fixed, are still present in every supported release, and will never be fixed, because fixing them would break fundamental Kubernetes behavior. If your scanner ingested those records, it has been clearing clusters that were never actually clean.
This is the post that turns that correction into an audit. First the four CVEs and the one check that tells you whether each applies to you, then what changed and why, then the five-step audit to run before you trust your next automated CVE-based patch decision.
The four CVEs at a glance
| CVE | What it is | Severity | All versions affected? | The one check |
|---|---|---|---|---|
| CVE-2020-8561 | kube-apiserver follows redirects to admission webhooks — SSRF toward internal networks | Medium (4.1) | Yes, since June 1 correction | Is --v below 10 and --profiling=false on every API server? |
| CVE-2020-8562 | DNS TOCTOU race bypasses API-server proxy IP restrictions | Low (3.1) | Yes, since June 1 correction | Does control-plane DNS return consistent answers between check and use (cached resolver)? |
| CVE-2021-25740 | Manually-set Endpoints/EndpointSlice IPs forward LoadBalancer/Ingress traffic cross-namespace | Low (3.1) | Yes, since June 1 correction | Who can write Endpoints and EndpointSlices in your cluster? |
| CVE-2020-8554 | spec.externalIPs / LoadBalancer status lets a Service author intercept traffic (MitM) | Medium | Yes — always was; record format standardized June 1 | Is DenyServiceExternalIPs (or the external-IP webhook) enforced? |
That table is the whole story in miniature: four issues, none patchable, each managed by configuration. If you already hardened all four, the June 1 correction changes nothing except your scanner output. If you relied on "we're on a fixed version" for any of them, keep reading — that version never existed.
What changed, and why now
On May 26, 2026, Pushkar Joglekar (Broadcom / SIG Security) and Tabitha Sable (Datadog / SRC / SIG Security) published Reconciling the Past: Correcting Records for Unfixed Kubernetes CVEs on the Kubernetes blog. The announcement was precise about the mechanism: while maturing the official Kubernetes CVE feed and generating official OSV (Open Source Vulnerabilities) files, the project found that the CVE records for CVE-2020-8561, CVE-2020-8562, and CVE-2021-25740 incorrectly included a fixed version field. The SRC corrected all three — plus a version-format standardization of the already-correct CVE-2020-8554 record — on June 1, 2026, as the post's update note confirms.
The reason the records were wrong is the interesting part. These are not bugs awaiting a patch. They are architectural design trade-offs that cannot be fully remediated in code without breaking things Kubernetes fundamentally depends on: standard HTTP redirect behavior that legitimate webhook integrations rely on (8561), DNS resolution flexibility that split-horizon and dynamic-IP environments need (8562), and the Endpoints API's core feature of letting networking tools point services at arbitrary IPs (25740). The SRC's framing is worth quoting directly: the project is moving away from a patch-only mindset toward accurately documenting architectural debt. Credit went to the researchers who found the issues — QiQi Xu, Javier Provecho, and others — and to Rory McCune, whose blog series on Kubernetes' unpatchable CVEs had been carrying this message long before the official records caught up.
Two consequences follow immediately. First, scanners that match findings against version ranges will now report these CVEs on clusters where they previously reported nothing. The May 26 post says so explicitly: correcting the records "may result in vulnerability scanners identifying these vulnerabilities in places where they were previously not detected." Second, every historical "clean" verdict your tooling produced against the old records is suspect — not because the scanner malfunctioned, but because its input data said a fixed version existed when none did.
Why scanner-clear is not the same as safe
Vulnerability scanners do not test exploits. They match observed versions against published ranges: if your kube-apiserver version is at or above the record's fixed version, the finding is suppressed. A wrong fixed-version field therefore produces exactly the worst kind of scanner output — a confident negative. Your dashboard said compliant, your audit trail said patched, and the exposure sat there the whole time, disclosed since 2020 and 2021.
Whether that exposure matters depends on your threat model, and the advisories are honest about the blast radius. All four issues require an authenticated actor with specific write permissions: someone who can configure admission webhooks (8561), someone reaching the API-server proxy (8562), someone who can write Endpoints or Services (25740, 8554). The original CVE-2020-8554 advisory names the highest-risk shape directly: multi-tenant clusters that grant tenants the ability to create and update services and pods. A single-tenant cluster where only platform admins hold those permissions has a much smaller window than a shared fleet where every tenant deploys services freely.
Here is the part that lands specifically on self-hosted fleets. A managed provider absorbs this class of event into its own control plane: it flips the API-server flags, audits the default roles, and ships the mitigation in a version you adopt by upgrading. When you run your own control plane on machines you own — Cluster API-provisioned Hetzner nodes, kubeadm-built control planes, Talos-managed hosts — there is no provider layer doing that work. Your patch workflow upgrades binaries; these four issues do not respond to binary upgrades at all. "We patched within 24 hours of every CVE" is true and irrelevant for this category. The correction therefore asks something different of a self-hosted operator than of a managed-cluster consumer: not a faster upgrade, but a configuration audit against mitigations that live entirely outside the release stream.
The audit: five checks before your next CVE-based patch decision
Run these in order. Each produces a yes/no answer, and each maps to one row of the table above plus the scanner hygiene that makes future answers trustworthy. Validate every change in a non-production cluster first — the SRC's own guidance, and good practice regardless.
1. Refresh every scanner database and re-baseline
Any scan result produced from a vulnerability database older than June 1, 2026 may still carry the false negatives. Update the databases first, then re-run the cluster and image scans, and expect the four CVEs to newly appear — their appearance is the correction working, not a regression.
# Trivy: refresh the vulnerability DB, then re-scan
trivy image --download-db-only
trivy k8s --report summary cluster
# Grype: same idea, different tool
grype db update
grype <your-cluster-image-or-sbom>Record the database build date alongside the results. From here on, "clean" means "clean against a post–June 1 database," and any historical clean verdict from before the correction should be annotated as unreliable for these four IDs.
2. Verify API-server flags for CVE-2020-8561
The mitigation is two flags on every kube-apiserver: log verbosity below 10 (so webhook response bodies never land in logs an attacker could steer) and profiling disabled (so nobody can raise verbosity at runtime). Check the actual running flags, not the manifest you think is deployed:
kubectl -n kube-system get pods -l component=kube-apiserver \
-o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{range .spec.containers[0].command[*]}{.}{"\n"}{end}{end}' \
| grep -E '^(kube-apiserver|--v=|--profiling)'You want --v at a value below 10 (the common default of 2 is fine) and --profiling=false on every API-server instance, in every cluster in the fleet. If your nodes are provisioned from a machine image or a static-pod template, fix the template — otherwise the next Cluster API machine roll reintroduces the exposure.
3. Audit who can write Endpoints for CVE-2021-25740
Since Kubernetes 1.22, the default edit and admin ClusterRoles no longer include write access to Endpoints and EndpointSlices — but that removal applies to clusters created on 1.22 or later. Clusters upgraded from older versions keep whatever their aggregated roles already granted, which makes this the highest-yield check for long-lived fleets. Inspect the aggregate and every custom role bound broadly:
# What does the aggregated edit role grant today?
kubectl get clusterrole system:aggregate-to-edit -o yaml | grep -B3 -A8 'endpoints'
# Which roles anywhere grant endpoints write, and who holds them?
kubectl get clusterroles,roles --all-namespaces -o json | python3 -c '
import json,sys
for r in json.load(sys.stdin)["items"]:
for rule in r.get("rules",[]):
res=set(rule.get("resources",[]))
if {"endpoints","endpointslices"} & res and set(rule.get("verbs",[])) & {"create","update","patch","*"}:
print(r["kind"],"/",r["metadata"].get("namespace","-"),"/",r["metadata"]["name"])
'Any broad binding with Endpoints write — tenant edit roles, CI service accounts, operator roles wider than they need to be — is the exposure. Trim the verbs, then reconcile the bindings. This is the one check most likely to find something real on a fleet that has been upgraded in place for years.
4. Verify control-plane DNS consistency for CVE-2020-8562
The TOCTOU exists because the API server resolves a name once to check it and again to connect, and the two answers can differ. The SRC's mitigation is a local caching resolver on control-plane nodes — dnsmasq with min-cache-ttl set — so both resolutions see the same answer. Verify the resolver is actually in the API server's path and the minimum TTL is enforced:
# On each control-plane node: is a caching resolver configured, and is the floor set?
grep -r min-cache-ttl /etc/dnsmasq* 2>/dev/null
cat /etc/resolv.confIf control-plane nodes resolve directly against an upstream recursive resolver with no local cache, the race is live. Note the trade-off the SRC names: pinning answers is exactly what breaks split-horizon or fast-changing DNS setups, so test name resolution for your webhooks and aggregated API servers after enabling the cache.
5. Verify ExternalIP restriction for CVE-2020-8554
The fourth CVE was never mis-recorded — its record always said all versions affected — but it belongs in this audit because it shares the shape: unfixable in-tree, managed by admission control. Since Kubernetes 1.21 the built-in answer is the DenyServiceExternalIPs admission controller; older clusters used the externalip-webhook sidecar. Confirm one of them is enforced:
# Is the admission controller enabled on the API server?
kubectl -n kube-system get pods -l component=kube-apiserver \
-o jsonpath='{.items[0].spec.containers[0].command}' | tr ' ' '\n' | grep -A1 admission-plugins
# Or is the webhook path deployed instead?
kubectl get validatingwebhookconfigurations | grep -i externalipIf neither is present, any principal who can create a ClusterIP service with spec.externalIPs can intercept traffic to that IP — the exact multi-tenant scenario the 2020 advisory warned about. Enable the admission controller (it rejects the field outright) or deploy the webhook (which restricts it to an allowlist), and then grep existing services for externalIPs entries that predate the enforcement.
Living with CVEs that will never be fixed
The durable lesson is not the five commands — it is the category they belong to. "Unfixed by design" is now an official status a CVE record can carry, and the SRC has shown it will correct the historical record to say so. A patch workflow built purely on "upgrade to the fixed version" has a hole shaped exactly like this category: the upgrade ships, the scanner goes green on every patchable issue, and the architectural exposures persist underneath, invisible until someone audits configuration rather than versions.
Two process changes close that hole. First, treat scanner databases as versioned inputs: pin the database date to every report, and re-baseline after feed corrections the same way you would after a scanner upgrade. Second, fold the mitigations above into the fleet's machine-lifecycle path — the API-server flags into the control-plane template, the RBAC audit into the post-upgrade checklist, the DNS and admission checks into node-conformance — so a fresh Cluster API roll or a new cluster build inherits them instead of rediscovering them. Fresh 1.22+ clusters already carry the RBAC half of this story; upgraded clusters and hand-rolled control planes carry the debt, which is precisely why the audit starts there.
Transparency that arrives six years late is still transparency worth acting on. The records are correct now. Make the fleet match them.
Running your own Kubernetes fleet on machines you own? Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on your own hardware, with the control plane yours to audit. Star the repo on GitHub or deploy your first app today.



