# Ingress-nginx CVE-2025-1974: What It Is and How to Fix It
> CVE-2025-1974 (IngressNightmare) is a critical RCE flaw in ingress-nginx affecting 40%+ of clusters. Learn how to detect and patch it.

Canonical: https://blog.abhimanyu-saharan.com/posts/ingress-nginx-cve-2025-1974-what-it-is-and-how-to-fix-it
Published: 2025-03-25
Last updated: 2025-05-24
Authors: Abhimanyu Saharan
Categories: Security, Kubernetes

Today, when I woke up and checked my RSS feed, one headline stood out immediately, **CVE-2025-1974**. It’s a new high-severity vulnerability in `ingress-nginx`, and it’s bad. Like _"**any pod in your cluster can potentially take over your entire Kubernetes environment without credentials**"_ bad.

Naturally, I dropped everything and dug into the advisory.

## So, What’s Going On?

The ingress-nginx maintainers just dropped patches for five security vulnerabilities. The most critical among them—**CVE-2025-1974**—has a **CVSS score of 9.8**. It allows configuration injection via the Validating Admission Controller, meaning any workload on the Pod network could potentially compromise your cluster.

Let that sink in: even if a user or service doesn’t have permission to create Ingress objects, it could still exploit this path—just by being on the same network.

For context, **ingress-nginx** is a widely used ingress controller in Kubernetes (deployed in 40%+ clusters). It translates Ingress resources into NGINX configurations to route external traffic to internal services. It's flexible, easy to deploy—and now, evidently, a big attack surface.

## Why This One's Especially Dangerous?

Ingress controllers usually require elevated privileges. But this particular flaw means that **even low-privileged pods can interact with the Validating Admission Controller** in unintended ways. Combine that with other config handling issues patched today, and you’re looking at a **cluster-wide exposure** scenario.

## Here's What You Must Do: Upgrade Immediately (Recommended)

**✅ Best-case fix: Upgrade to a patched version.**

**Patched versions available:**

- `v1.12.1`
- `v1.11.5`

Upgrading ensures you're protected not just from CVE-2025-1974 but also from four other related vulnerabilities fixed in this release.

### Pros

- Full protection from all known CVEs.
- No feature regression; you can continue using the Validating Admission Controller.
- Long-term fix—no need for workaround maintenance.

### Cons

- Requires a cluster upgrade cycle, which may be gated in large orgs or restricted environments.
- May cause temporary downtime depending on your deployment strategy.

## Can't Upgrade Right Now? Disable the Validating Admission Controller (Workaround)

If you’re unable to upgrade but still need to take action immediately, the next best thing is to disable the Validating Admission Controller.

### 🔧 If installed via Helm:

```
helm upgrade <release-name> ingress-nginx \
  --reuse-values \
  --set controller.admissionWebhooks.enabled=false
```

### 🔧 If installed manually:

Remove the `--validating-webhook` container args and associated webhook configurations from your Deployment or DaemonSet.

### ⚠️ Reminder

**Re-enable** the Validating Admission Controller after you’ve upgraded to a patched version—it’s there for a reason: to prevent misconfigured Ingress resources from being applied.

### Pros

- Quick to apply.
- Mitigates the exploit path.

### Cons

- Disables important guardrails; invalid Ingress resources will not be caught.
- Still vulnerable to other less-severe issues if not upgraded later.
- Requires manual tracking to ensure it’s re-enabled later.

## Still Can't Upgrade or Disable? Block the Exploit at the Network Layer

If you're locked out of upgrading _and_ cannot disable the webhook due to organizational or technical constraints, there’s still a fallback:

**Use a DaemonSet to block external access to the webhook port (8443) using iptables, while allowing kube-apiserver traffic through.**

Here’s how it works:

- A DaemonSet runs on every node.
- It fetches the Kubernetes API server’s IP.
- It applies an iptables rule to drop external traffic to port 8443 (the webhook).
- It allows only the API server to talk to the webhook.

### YAML Snippet

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: allow-get-kubernetes-endpoint
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    resourceNames: ["kubernetes"]
    verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: allow-get-kubernetes-endpoint-binding
  namespace: default
subjects:
  - kind: ServiceAccount
    name: default
    namespace: kube-system
roleRef:
  kind: Role
  name: allow-get-kubernetes-endpoint
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: webhook-port-blocker
  namespace: kube-system
  labels:
    app: webhook-port-blocker
spec:
  selector:
    matchLabels:
      app: webhook-port-blocker
  template:
    metadata:
      labels:
        app: webhook-port-blocker
    spec:
      hostNetwork: true
      serviceAccountName: default
      volumes:
        - name: shared
          emptyDir: {}
        - name: sa-token
          projected:
            sources:
              - serviceAccountToken:
                  path: token
                  expirationSeconds: 3600
              - configMap:
                  name: kube-root-ca.crt
              - downwardAPI:
                  items:
                    - path: namespace
                      fieldRef:
                        fieldPath: metadata.namespace
      initContainers:
        - name: fetch-apiserver-ips
          image: bitnami/kubectl:1.20
          command:
            - sh
            - -c
            - |
              echo "[+] Fetching all Kubernetes API server IPs..."
              kubectl get endpoints kubernetes -n default -o jsonpath='{.subsets[0].addresses[*].ip}' | tr ' ' '\n' > /shared/apiserver-ips

              echo "[+] IPs written to /shared/apiserver-ips:"
              cat /shared/apiserver-ips
          volumeMounts:
            - name: shared
              mountPath: /shared
            - name: sa-token
              mountPath: /var/run/secrets/kubernetes.io/serviceaccount
              readOnly: true
      containers:
        - name: iptables
          image: alpine:3.19
          securityContext:
            privileged: true
          command:
            - sh
            - -c
            - |
              apk add --no-cache iptables ipset >/dev/null

              echo "[+] Waiting for /shared/apiserver-ips..."
              while [ ! -s /shared/apiserver-ips ]; do sleep 1; done

              echo "[+] Creating or flushing ipset 'apiserver-ips'..."
              ipset create apiserver-ips hash:ip 2>/dev/null || ipset flush apiserver-ips

              echo "[+] Adding allowed IPs to ipset..."
              while read -r IP; do
                ipset add apiserver-ips "$IP" 2>/dev/null || true
              done < /shared/apiserver-ips

              echo "[+] Inserting new iptables rule using ipset..."
              iptables -I INPUT -p tcp --dport 8443 -m set ! --match-set apiserver-ips src -j DROP

              echo "[+] Final iptables rules:"
              iptables -L INPUT -n --line-numbers | grep 8443

              tail -f /dev/null
          volumeMounts:
            - name: shared
              mountPath: /shared
          resources:
            requests:
              cpu: 25m
              memory: 32Mi
            limits:
              cpu: 100m
              memory: 64Mi
      tolerations:
        - operator: Exists
```

### Pros

## FAQ

### What is CVE-2025-1974 and why is it critical?

CVE-2025-1974 is a high-severity vulnerability (CVSS 9.8) in `ingress-nginx` that allows configuration injection via the Validating Admission Controller. It enables any pod on the cluster network to potentially compromise the entire Kubernetes environment, even without Ingress creation permissions.

### How does this vulnerability affect Kubernetes clusters using ingress-nginx?

Even low-privileged pods can exploit the Validating Admission Controller to inject malicious configuration. Since `ingress-nginx` runs with elevated privileges in many clusters, this creates a pathway for full-cluster compromise.

### What’s the recommended fix for CVE-2025-1974?

Upgrade immediately to a patched version of `ingress-nginx`:

- v1.12.1
- v1.11.5  
This addresses CVE-2025-1974 and four other related vulnerabilities without removing key features.

### What are the alternatives if an upgrade isn’t possible right away?

You can disable the Validating Admission Controller temporarily by removing its container args and webhook configs. However, this also disables safeguards against invalid Ingress resources, so it should be re-enabled post-upgrade.

### Is there a last-resort mitigation if neither upgrade nor disabling is viable?

Yes. As a last resort, you can deploy a DaemonSet that configures `iptables` rules to block all external traffic to port 8443, used by the webhook, while allowing access only from the Kubernetes API server. This mitigates the vulnerability at the network layer, but use it with caution, as it has not been widely tested in production environments.
