IL-0053 Wiz · 2025-03-24 (published)kubernetessecurity
To validate an Ingress, the controller's admission webhook builds a temporary NGINX configuration from a template and the Ingress object and checks it with `nginx -t`. Several values went into that file without proper sanitization: the auth-url annotation (CVE-2025-24514, not in 1.12.0, which checks annotations against strict regular expressions), the auth-tls-match-cn annotation (CVE-2025-1097, which also needs an auth-tls-secret annotation naming any TLS secret in the cluster), and the Ingress UID in the mirror parser (CVE-2025-1098). Each lets the sender inject arbitrary NGINX directives.
CVE-2025-1974 turns that injection into code execution during `nginx -t`. load_module only works at the top of the file, but the ssl_engine directive of the OpenSSL module, undocumented for this use, loads a shared library from any position. To place a library on the pod, the attacker sends a request body larger than 8KB to the NGINX running in the same pod, which buffers it to a temporary file. NGINX deletes the file at once, but a Content-Length larger than the body keeps the process waiting with the file descriptor open, so the file stays reachable under ProcFS; the attacker guesses the PID and descriptor number and points ssl_engine at that path.
The code runs with the controller's service account, which by default can read Secrets in all namespaces, so the attacker can take over the cluster. The attack vector has a CVSS v3.1 base score of 9.8, and Wiz estimates about 43% of cloud environments were vulnerable. Kubernetes released internal patches for the injection flaws on 7 February 2025, removed NGINX configuration testing from the admission controller to resolve CVE-2025-1974 (reported to Wiz on 20 February), and disclosed on 24 March 2025 with fixed versions 1.12.1 and 1.11.5. A later note on the post says ingress-nginx reached end of life on 12 November 2025 and maintenance stops in March 2026.
This is a vulnerability report, not an outage, so nothing failed visibly. A cluster is exposed if it runs Ingress NGINX Controller older than 1.12.1 or 1.11.5 with its validating admission webhook enabled. Wiz suggests `kubectl get pods --all-namespaces --selector app.kubernetes.io/name=ingress-nginx` to find it. The webhook accepts AdmissionReview requests over HTTP without authentication from any pod, and Wiz found more than 6,500 clusters exposing it to the public internet.
The exploit Wiz describes shows up as AdmissionReview requests sent straight to the webhook rather than by the API server, carrying Ingress annotations such as `nginx.ingress.kubernetes.io/auth-url: "http://example.com/#;\ninjection_point"`, and as large request bodies sent to the NGINX in the same pod with a Content-Length longer than the body.
Root cause ? Software defect
Found by Wiz Research in a code review of the admission controller, not by an operator.
–
Admission webhooks often run as web servers inside the cluster without authentication and with relatively high privileges, so any pod can reach them, and the flaws pair well with SSRF in an application. Wiz concludes that `nginx -t` should be considered harmful when it processes unsanitized user input. Wiz recommends upgrading, keeping the webhook off the internet and allowing only the API server to reach it with network policies. If upgrading must wait, disable the webhook (Helm: controller.admissionWebhooks.enabled=false; manual installs: delete the ValidatingWebhookConfiguration ingress-nginx-admission and remove --validating-webhook from the controller) and enable it again after the upgrade.
same root cause · shared Ingress controller
same root cause · shared Ingress controller
same root cause · shared Admission webhook
same root cause · shared Ingress controller
same root cause · shared Ingress controller
same root cause · shared Ingress controller