← Back to Research

IngressNightmare: Cluster Takeover From a Single Unauth Packet (CVE-2025-1974)

CVE-2025-1974 — CVSS 9.8. Affects ingress-nginx controller v1.11.0 and earlier. Unauthenticated RCE into a cluster-admin-equivalent service account. Wiz telemetry shows roughly 40% of clusters still haven't patched 14 months after disclosure.

The admission webhook runs with cluster-admin-equivalent service account rights. It parses attacker-controlled Ingress annotations through a template that executes shell. Any pod that can reach port 8443 on the controller wins the cluster. Wiz telemetry shows roughly 40% of clusters still haven't patched 14 months after disclosure. The catch-up patch is boring. The blast radius isn't.

What the bug is

CVE-2025-1974 is four chained primitives in the ingress-nginx admission webhook. Affected: ingress-nginx controller v1.11.0 and earlier. CVSS 9.8. Unauthenticated RCE. The Wiz research team named it IngressNightmare because of how thoroughly it collapses the cluster-trust model — one crafted AdmissionReview request and the attacker owns every workload, every secret, every container registry credential mounted inside the cluster.

It's not a zero-day anymore. It's a 14-month-old patch that tens of thousands of teams still haven't applied. The Wiz census published in March 2026 scanned 186,000 internet-reachable Kubernetes control planes and found 73,000 of them exposing a vulnerable ingress-nginx version.

The technical chain

Five hops from unauth network reachability to cluster-admin.

  1. Attacker submits a crafted Ingress object, or sends an AdmissionReview API call directly to the webhook on port 8443. No auth required — the webhook endpoint accepts requests from anywhere in pod networking by default.
  2. The controller pushes the annotation values through an nginx configuration template. Specific annotations (including nginx.ingress.kubernetes.io/auth-url and several snippet variants) are interpolated without sufficient escaping.
  3. The rendered config is handed to nginx -t for validation. The template injection produces a shell command that executes inside the controller pod during the dry-run validation.
  4. The controller pod holds a service-account token at /var/run/secrets/kubernetes.io/serviceaccount/token with cluster-wide get/list/watch/create/update/delete on virtually every resource kind. The attacker reads the token.
  5. With that token the attacker talks directly to the Kubernetes API server: dumps every secret, mounts privileged debug pods on arbitrary nodes, pivots to cloud-provider metadata, or simply deploys a cryptominer on every worker.

Why 40% are still vulnerable

Operator teams often leave ingress-nginx on an older chart because an upgrade requires a 30-second control-plane blip during pod rotation. The blip isn't the problem. The problem is the ritual around justifying the blip: a change window, a ticket, a reviewer, an on-call handoff, a rollback plan for a patch that has shipped cleanly on every cluster it's been tested against for a year.

Every week that passes, the probability that the cluster gets hit rises. Every week you justify not patching, you pay interest on the decision.

The fix

Upgrade to ingress-nginx v1.12.1 or later. Then restrict network access to the admission webhook with a NetworkPolicy — the webhook should only be reachable from the Kubernetes API server, not from workload pods. The relevant NetworkPolicy:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: ingress-nginx-webhook-lockdown
  namespace: ingress-nginx
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/component: controller
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - protocol: TCP
          port: 8443

Upgrade first, then apply the NetworkPolicy. In reverse order you risk a broken admission flow during the upgrade.

How Celvex Sentry catches this

Cloud & Infrastructure scans for the webhook service on internal ranges during authenticated cloud runs and fingerprints the ingress-nginx version from the controller's response headers. When the version resolves to v1.11.0 or earlier, the chain engine escalates the finding to Critical because cluster takeover pairs with the registry-exfiltration chain already tracked in the attack graph — a single unauth packet becomes full tenant compromise inside two hops.

Pen-testers hand you a PDF once a year; Celvex Sentry runs every attack they would, every week, and proves the ones that still work — with a fix attached.

Sources

Get your exposure check — full report in 4-24 hours

Full report in 4-24 hours. Real assessment on production-grade infrastructure. Paying customers get priority capacity.

Queue My Assessment