Nov 7, New York: Romaric speaks at SREday NYC: SRE in the era of AI

ingress-nginx Is Retired and a New CVE Just Landed: The 24-Hour Mitigation Runbook and What to Run Instead

ingress-nginx reached end of maintenance in 2026, so any CVE filed after that date - including CVE-2026-116472 - will never get an official upstream patch. Here is the four-step containment runbook you can apply in 24 hours, a fair comparison of the maintained ingress controllers and Gateway API implementations that should replace it, and a hostname-by-hostname migration plan with rollback.

Romaric Philogene
CEO & Co-founder
NOV 8, 2026 · 13 MIN
ingress-nginx Is Retired and a New CVE Just Landed: The 24-Hour Mitigation Runbook and What to Run Instead

No patch is coming for CVE-2026-116472, so stop waiting for one. The Kubernetes project ended ingress-nginx maintenance in March 2026, and the official advisory for this CVE says it plainly: "Kubernetes will not be issuing a fix for this CVE" (Kubernetes advisory, issue #143852). You can contain it today with one ConfigMap change, then you need to plan your exit.

The good news is that this specific CVE is rated low. The bad news is that it will not be the last one, and every future ingress-nginx CVE will get the same answer.

Qovery · Infrastructure control plane
A control plane for platform teams and their coding agents
Learn more

Key Points:

  • No upstream fix exists or will exist. CVE-2026-116472 was published on November 5, 2026 with a CVSS 3.1 score of 2.7 (Low), and every ingress-nginx version is listed as affected (CVE.org record). The Kubernetes Security Response Committee still publishes the advisory, but no patched release or image will follow.
  • The fastest mitigation is one ConfigMap key. Set annotations-risk-level: Medium in the controller ConfigMap, or reject the mirror-target annotation with an admission policy. Both are the official workarounds.
  • Who can create an Ingress is your real privilege boundary. CVE-2026-116472 and three of the five IngressNightmare CVEs required only Ingress write access. CVE-2025-1974 needed no credentials at all, just network access to the admission webhook.
  • Treat any fork as a short bridge. SUSE already ships a fix in its Rancher Prime fork, and Microsoft patches the AKS add-on through November 2026. Use vendor-backed forks to buy weeks while you migrate.
  • Replace it with a maintained Gateway API implementation. Envoy Gateway, Istio, Cilium, Traefik, NGINX Gateway Fabric, Kong, or your cloud's controller all pass Gateway API conformance today. InGate, the planned successor, was retired before it matured.
  • Qovery customers did not run this by hand. We migrated the clusters we manage from ingress-nginx to Envoy Gateway as a platform rollout, in customers' own AWS, GCP, Azure, Scaleway, or existing Kubernetes clusters.

What does "ingress-nginx maintenance ended" actually mean for a CVE like CVE-2026-116472?

It means the CVE gets an advisory and never gets a fix. The Kubernetes Security Response Committee still assigns and publishes CVEs for ingress-nginx, but there is no release pipeline left to ship a patched version, so your only paths are mitigation, a vendor fork, or replacement.

The retirement was announced on November 11, 2025: "Best-effort maintenance will continue until March 2026. Afterward, there will be no further releases, no bugfixes, and no updates to resolve any security vulnerabilities that may be discovered" (Kubernetes blog). The last controller release, v1.15.1, shipped on March 19, 2026, and the GitHub repository is now archived (ingress-nginx releases).

In practice, retirement means:

  • No new release tags and no new controller images.
  • No backports to older minors.
  • Advisories without fixes. The SRC still files CVEs, as it did for CVE-2026-116472, but the remediation section points you to "your vendor".
  • Existing deployments keep running. Helm charts and images stay available, which is exactly why so many clusters still run it.

What CVE-2026-116472 actually is

I checked the record on CVE.org, NVD, and the GitHub Advisory Database before writing this. It is real, and it is a low-severity self-DoS:

  • Mechanism: due to a missing check, the mirror-target annotation can target an unauthenticated configuration API inside the controller. Corrupting it drops all traffic through that ingress-nginx instance until a config change or restart.
  • Who can trigger it: a user with permission to create an Ingress. That is why the CVSS vector says PR:H and the score is 2.7 (Kubernetes advisory).
  • Affected versions: all of them. SUSE fixed it in 1.15.2-prime1 of its RKE2 fork.

Low severity is not a reason to relax. The triage rule for any ingress-nginx CVE published after March 2026 is the same regardless of score: mitigate now, decide fork versus replace this week, finish the migration this quarter.

How big is the blast radius?

Big. Wiz found that over 41% of internet-facing clusters ran ingress-nginx, and that about 43% of cloud environments were vulnerable to the IngressNightmare chain in March 2025, with over 6,500 clusters exposing the admission controller to the internet (Wiz Research).

Check managed add-ons too, because in many clusters nobody on the current team installed it. The AKS application routing add-on is built on ingress-nginx, and Microsoft supports critical patches for it only through November 2026 (Microsoft Learn). RKE2 shipped ingress-nginx as its default until v1.36 switched new clusters to Traefik (RKE2 docs).

An unpatchable component in your request path is also an audit finding. Your scanner will flag it forever, and your SOC 2 or PCI DSS auditor will ask for either a remediation date or a signed risk acceptance. CISA's BOD 26-04 lists decommissioning as a valid remediation, and for a retired project that is the only permanent one.

How do we mitigate ingress-nginx right now, in the next 24 hours?

Shrink what an Ingress author and a network attacker can do to the controller in four moves: block high-risk annotations, block mirror-target at admission, tighten RBAC, and isolate the controller with NetworkPolicy. One engineer can apply all of it in about 4 to 6 hours, and the first two moves fully cover CVE-2026-116472.

Step 1: Inventory (15 minutes)

Find every controller, its exact image, and who owns it:

BASH
kubectl get pods -A -l app.kubernetes.io/name=ingress-nginx \
  -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.spec.containers[*].image}{"\n"}{end}'
helm list -A | grep -i nginx
kubectl get ingressclass
aws eks list-addons --cluster-name <cluster-name>
az aks show -g <resource-group> -n <cluster-name> --query ingressProfile

Then find Ingresses that already use mirror-target. The advisory says localhost addresses in that annotation may indicate an exploit attempt:

BASH
kubectl get ingress -A -o json | jq -r '.items[]
  | select(.metadata.annotations["nginx.ingress.kubernetes.io/mirror-target"] != null)
  | "\(.metadata.namespace)/\(.metadata.name)\t\(.metadata.annotations["nginx.ingress.kubernetes.io/mirror-target"])"'

Step 2: Lower the annotation risk level (30 minutes)

annotations-risk-level defaults to High, and mirror-target is rated High (annotation risk table). Setting it to Medium rejects every High and Critical annotation, which is the official workaround for this CVE. allow-snippet-annotations already defaults to false on recent versions (ConfigMap docs), so confirm nobody turned it back on.

This breaks things. List what will stop applying first:

BASH
kubectl get ingress -A -o json | jq -r '.items[] | .metadata as $m
  | ($m.annotations // {}) | keys[]
  | select(test("nginx.ingress.kubernetes.io/(auth-url|auth-signin|auth-tls-error-page|auth-tls-match-cn|mirror-host|mirror-target|modsecurity-transaction-id|proxy-ssl-name|server-alias|upstream-hash-by|.*-snippet)$"))
  | "\($m.namespace)/\($m.name)\t\(.)"'

If that list includes auth-url for external auth, skip to the admission policy in Step 3 instead. Otherwise, apply through Helm so the next upgrade does not revert it:

BASH
helm upgrade ingress-nginx ingress-nginx/ingress-nginx -n ingress-nginx --reuse-values \
  --set controller.allowSnippetAnnotations=false \
  --set-string controller.config.annotations-risk-level=Medium

Step 3: Block mirror-target at admission and tighten RBAC (1 to 2 hours)

If you cannot lower the risk level, reject the one dangerous annotation with a built-in ValidatingAdmissionPolicy (GA since Kubernetes 1.30):

YAML
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: deny-nginx-mirror-target
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups: ["networking.k8s.io"]
      apiVersions: ["v1"]
      operations: ["CREATE", "UPDATE"]
      resources: ["ingresses"]
  validations:
  - expression: >-
      !has(object.metadata.annotations) ||
      !('nginx.ingress.kubernetes.io/mirror-target' in object.metadata.annotations)
    message: "mirror-target is blocked: CVE-2026-116472 has no upstream fix"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: deny-nginx-mirror-target
spec:
  policyName: deny-nginx-mirror-target
  validationActions: ["Deny"]

Then audit who can write Ingress objects. The ingress-nginx README says the project "assumes that users that can create Ingress objects are administrators of the cluster" (README). Treat that list of identities exactly that way:

BASH
kubectl auth can-i create ingresses.networking.k8s.io -A --as=system:serviceaccount:<ns>:<sa>
kubectl who-can create ingresses.networking.k8s.io --all-namespaces   # krew plugin: who-can

The default chart ClusterRole lets the controller list and watch Secrets in every namespace. If one controller serves one namespace, set controller.scope.enabled=true, controller.scope.namespace=<ns>, and rbac.scope=true to swap it for a namespaced Role. If it serves the whole cluster, you cannot scope it without splitting controllers, so accept that and move faster on the migration.

Step 4: Isolate the controller with NetworkPolicy (1 to 2 hours)

Do not block the controller's egress to the API server. It watches Ingresses, Services, and Secrets through that connection and stops working without it. Lock down inbound access to the admission webhook instead, which is the path CVE-2025-1974 used, and block the cloud metadata endpoint:

YAML
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: ingress-nginx-lockdown
  namespace: ingress-nginx
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/component: controller
  policyTypes: ["Ingress", "Egress"]
  ingress:
  - ports:
    - port: 80
    - port: 443
  - from:
    - ipBlock:
        cidr: 10.0.0.0/28   # replace with your control plane CIDR
    ports:
    - port: 8443
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 169.254.169.254/32

Add a rule for port 10254 if Prometheus scrapes the controller. Kubelet probes keep working because traffic from the pod's own node is always allowed (NetworkPolicy docs). Test the control plane CIDR in staging first: a wrong value makes every Ingress create fail.

Edge filtering and detection

A WAF rule will not help with CVE-2026-116472, because the attack arrives as an Ingress object through the Kubernetes API, not as an HTTP request. Keep AWS WAF, Google Cloud Armor, Azure WAF, or Cloudflare rules for future request-path CVEs that have a stable signature.

For detection, search Kubernetes audit logs for Ingress create and update events from unusual service accounts, check controller logs for unexpected reloads, and alert on any mirror-target value pointing at 127.0.0.1 or localhost.

ActionExact key or commandAttack class it blocksTimeBreaking-change riskKeep after migration?
Inventory controllers and add-onskubectl get pods -A -l app.kubernetes.io/name=ingress-nginxUnknown, unowned installs15 minNoneYes, quarterly
Lower annotation riskannotations-risk-level: MediumCVE-2026-116472, annotation config injection30 minHigh: auth-url, mirror, server-alias stop applyingYes, as an annotation policy
Disable snippetsallow-snippet-annotations: "false"Arbitrary nginx directive injection10 minHigh if teams use snippetsYes
Deny mirror-targetValidatingAdmissionPolicy aboveCVE-2026-11647230 minLowNo, ingress-nginx specific
Scope controller RBACcontroller.scope.enabled=true, rbac.scope=trueCluster-wide Secret theft after RCE1 hMedium: single namespace onlyYes, least privilege
Restrict webhook accessNetworkPolicy on port 8443Unauthenticated webhook RCE (CVE-2025-1974 class)1 to 2 hMedium if CIDR is wrongYes
Block metadata egressNetworkPolicy except: 169.254.169.254/32Cloud credential theft after RCE15 minLowYes
Edge WAF ruleAWS WAF, Cloud Armor, Azure WAF, CloudflareRequest-path exploits with a signature2 to 4 hLow to mediumYes
Ship faster on infrastructure you control.
Qovery gives your team self-service deployments and managed cluster upgrades on your own AWS, GCP, Azure, or Scaleway account - or your existing Kubernetes cluster. Start deploying in under 10 minutes.

Should we run a community fork of ingress-nginx instead of migrating?

Run a vendor-backed fork only as a time-boxed bridge, for 4 to 8 weeks, while the migration runs in parallel. A fork without a named vendor, a security contact, and signed images is a dependency on a stranger in your request path, which is worse than the retired original.

The credible forks today come from vendors you may already pay. SUSE fixed CVE-2026-116472 in its Rancher Prime fork (Kubernetes advisory), and Microsoft patches the AKS add-on through November 2026. Both vendors also tell you to leave: RKE2 removes ingress-nginx for new clusters in v1.37, and AKS points to Gateway API.

Before adopting any fork, get answers to five questions:

  • Who funds it, and what happens when that funding stops?
  • Does it track upstream nginx security releases, not just the controller Go code?
  • Where is the image hosted, who can push to it, and is it signed with provenance and an SBOM?
  • Is there a published security contact and response SLA?
  • What is its own end-of-life date?

"We'll just build our own image from the last commit" is a permanent commitment. You now own nginx CVE tracking, Go dependency CVEs, base image rebuilds, and CI, forever. I've seen teams pick that path to avoid a two-week migration and still be carrying it a year later.

OptionCost (my estimate)How long it buys youWho it fitsFailure mode
Mitigate in place1 to 2 engineer-daysUntil the next CVE that config cannot blockEveryone, as step oneA request-path RCE with no config workaround
Vendor fork (SUSE, AKS add-on)1 to 3 days to switch, plus a contractUntil the vendor's own end dateTeams already on RKE2 or AKSVendor date arrives before your migration does
Self-built fork3 to 5 engineer-days per quarter, foreverAs long as you keep payingAlmost nobodySilent drift from upstream nginx security fixes
Migrate nowDays to weeks, scoped by annotation usageYears, on a maintained projectEveryone, eventuallyUnderestimating annotation translation

InGate is not an option. The Kubernetes project states that "InGate development never progressed far enough to create a mature replacement; it will also be retired" (Kubernetes blog).

What should replace ingress-nginx long term, and how do the options compare?

Replace ingress-nginx with a maintained controller that passes Gateway API conformance and has a real security response process. SIG Network and the SRC "recommend that all Ingress NGINX users begin migration to Gateway API or another Ingress controller immediately" (Kubernetes blog), and choosing another Ingress-only controller just schedules the next migration.

Pick by context:

  • Single cloud, plain L7 routing and TLS: your cloud's controller (AWS Load Balancer Controller, GKE Gateway, Azure Application Gateway for Containers) has the lowest ops burden.
  • Portability across clouds: Envoy Gateway or Traefik.
  • Already running a service mesh: use Istio's gateway.
  • Already running Cilium as CNI: Cilium Gateway.
  • Want to keep an nginx data plane: NGINX Gateway Fabric, with the understanding that annotations do not carry over.

Status below comes from the Gateway API implementations page and the CNCF landscape as of November 2026. Gateway API itself is at v1.7.0, released October 29, 2026 (Gateway API releases).

ControllerMaintainer and CNCF maturityData planeGateway API statusingress-nginx annotation parityOps burdenBest fit
Envoy GatewayEnvoy project, CNCF Graduated (2018)EnvoyConformantNone native; ingress2gateway has an Envoy Gateway emitterMediumMulti-cloud default
Istio GatewayIstio, CNCF Graduated (2023)EnvoyConformant (Gateway and Mesh)None nativeHigh unless you already run IstioMesh users
Cilium GatewayCilium, CNCF Graduated (2023)Envoy with eBPFConformant (Gateway and Mesh)None nativeLow if Cilium is your CNICilium CNI clusters
Traefik ProxyTraefik Labs, not a CNCF projectTraefikConformantPartial, via its Ingress NGINX providerLow to mediumFastest like-for-like move
NGINX Gateway FabricF5 NGINX, not a CNCF projectNGINXConformantNone, different config modelMediumTeams that want nginx
Kong (Kong Operator)Kong Inc., not a CNCF projectKong GatewayConformantNone nativeMedium to highAPI gateway needs
ContourProject Contour, CNCF Incubating (2020)EnvoyNot listed on the page todayNone nativeMediumExisting Contour users
HAProxy Kubernetes IngressHAProxy Technologies, not a CNCF projectHAProxyNot listed; N42 Gateway is the listed HAProxy implementationNone nativeMediumHAProxy shops
AWS Load Balancer ControllerAWSAWS ALB and NLBPartially conformantNoneLowEKS only
GKE GatewayGoogleGoogle Cloud load balancersConformantNoneLowGKE only
Azure Application Gateway for ContainersMicrosoftAzure managedNot listed; supports Ingress and Gateway API per MicrosoftNoneLowAKS only
InGateKubernetes SIG Networkn/aRetired before maturityn/an/aNobody

Annotations are the real migration cost. Rewrite rules with capture groups, snippets, auth-url and auth-signin external auth, cookie-based canaries, session affinity, proxy-body-size, and timeouts all need translation. ingress2gateway (v1.2.0, July 2026) converts common ingress-nginx annotations, but its README says it "is not intended to copy annotations", and it flags capture-group rewrites and cookie canaries as unsupported.

Gateway API also fixes the root problem. GatewayClass and Gateway belong to the platform team, HTTPRoute belongs to app teams, so you stop hand-reviewing every Ingress for dangerous annotations.

What does a safe migration off ingress-nginx look like, step by step?

Install the new controller beside the old one and move traffic one hostname at a time. A parallel install with its own GatewayClass and load balancer turns rollback into a DNS change measured in minutes.

  1. Install side by side. Give the new controller its own GatewayClass and load balancer. Lower DNS TTLs to 60 seconds a day before cutover.
  2. Translate, then read the diff. Run ingress2gateway print --providers=ingress-nginx and list every annotation it could not convert. Size the project from that list.
  3. Validate on real hostnames. Read five ingress-nginx behaviors that Gateway API does not copy, such as case-insensitive prefix regex and automatic trailing-slash redirects. A preview environment per pull request catches these with real certificates before production does.
  4. Shift one hostname at a time. Start with the lowest-traffic host and keep the hardened ingress-nginx live until the last one moves.
  5. Test what always breaks. cert-manager HTTP-01 challenges, external-dns record ownership, WebSockets, gRPC, large request bodies, client IP preservation through proxy protocol and X-Forwarded-For, and sticky sessions.
  6. Decommission completely. Delete the Deployment, RBAC, the ValidatingWebhookConfiguration, and the cloud load balancer. Confirm nothing still uses the old class with kubectl get ingress -A -o wide. An idle AWS ALB or NLB still bills $0.0225 per hour, about $16 a month before capacity units (AWS pricing), and it stays an exposed endpoint.

A handful of simple hostnames takes days. Heavy snippet, external auth, and canary usage takes weeks. Our own move across the clusters Qovery manages held to the architecture we planned, but the calendar slipped by seven months, mostly because we would not force production clusters onto a stack their owners had not validated (Qovery engineering).

How do we stop the next retired-component fire before it starts?

Treat ingress, CNI, and cluster add-ons as versioned platform surface with a named owner, a tested upgrade path, and an exit plan. The real failure behind this CVE is a load-bearing component in the request path that nobody owned.

  • Keep an add-on inventory with maintainer health, CVE history, CNCF maturity, and end-of-life dates. Review it quarterly.
  • Require CNCF graduation or a vendor support contract for anything in the request path. Incubating projects need a named internal owner.
  • Standardize on Gateway API so the next swap is a GatewayClass change, not a manifest rewrite in every team's repo.
  • Measure time-to-upgrade as a platform SLO. If upgrading your ingress controller is scary, the CVE is not your problem - your upgrade path is.

This is the work Qovery takes off your plate. Qovery is an internal developer platform that deploys and operates your apps inside your own AWS, GCP, Azure, Scaleway, or existing Kubernetes cluster, so your cloud bill, discounts, and data stay in your account. Qovery is not an ingress controller. It manages the ingress layer and cluster upgrades for you, which is how we moved our customers from ingress-nginx to Envoy Gateway as a phased rollout with a rollback at every step (the plan).

Teams get git-push deployments, preview environments per pull request to validate routing changes, per-environment RBAC, and environment auto-stop, without a dedicated DevOps engineer babysitting add-on versions.

How do I run this migration from Claude Code or Cursor with Qovery?

Install the Qovery Agent Skills once and your coding agent can spin up a preview environment in your own cloud account, deploy the new routing path, and validate it before you touch production DNS. The skills handle deployment, and the MCP Server operates what already exists, read-only by default.

Install for every compatible agent (Claude Code, Cursor, Codex, OpenCode, Gemini CLI), globally:

BASH
curl -fsSL https://skill.qovery.com/install.sh | bash

Or scope the skills to the current project:

BASH
curl -fsSL https://skill.qovery.com/install.sh | bash -s -- --project

Add the MCP Server to Claude Code (OAuth, read-only by default) so the agent can inspect environments without changing them:

BASH
claude mcp add --transport http qovery https://mcp.qovery.com/mcp --callback-port 4242

Enable write access only when you explicitly want the agent to act. It also requires turning on write access in the Qovery Console:

BASH
claude mcp add --transport http qovery "https://mcp.qovery.com/mcp?read_write=true" --callback-port 4242

Then ask in plain language: "spin up a preview environment on my AWS account and validate the new ingress routing before I cut DNS over". The relevant skills are qovery-onboard, qovery-deploy, qovery-preview, and qovery-troubleshoot. Setup details are in the AI agent quickstart and the Claude Code integration page.

Frequently asked questions
Is there an official patch for CVE-2026-116472 in ingress-nginx?

No. The Kubernetes advisory for CVE-2026-116472 states that Kubernetes will not issue a fix because ingress-nginx maintenance ended in March 2026. The official mitigations are setting annotations-risk-level to Medium or Low, or rejecting the mirror-target annotation with an admission controller. SUSE ships a fix in version 1.15.2-prime1 of its Rancher Prime fork.

What is the fastest mitigation if I cannot migrate off ingress-nginx this week?

The fastest ingress-nginx mitigation is setting annotations-risk-level: Medium in the controller ConfigMap, which blocks every High and Critical annotation, including mirror-target. Check first whether you rely on auth-url, mirror, or server-alias annotations, because they stop applying. If you do, use a ValidatingAdmissionPolicy that rejects only mirror-target, then restrict who can create Ingress objects.

Which ingress controller should replace ingress-nginx in 2026?

The best ingress-nginx replacement in 2026 depends on context. Use your cloud's controller for single-cloud L7 routing, Envoy Gateway or Traefik for multi-cloud portability, Istio's gateway if you already run a mesh, and Cilium Gateway if Cilium is your CNI. Prefer a Gateway API conformant implementation from the official implementations page over another Ingress-only controller.

Is a community fork of ingress-nginx safe to run in production?

A community fork of ingress-nginx is safe only as a short bridge, and only if a named vendor backs it with signed images, a security contact, and a published end date. SUSE's Rancher Prime fork and Microsoft's AKS add-on meet that bar for now. An anonymous fork, or one you build yourself from the last commit, moves the maintenance burden onto your team permanently.

Do I have to move to Gateway API, or can I stay on the Ingress API?

You can stay on the Ingress API, because Ingress is not removed from Kubernetes, and the Kubernetes project lists maintained Ingress controllers as an acceptable path. Gateway API is the recommended direction, though, and it replaces annotation sprawl with typed routes and a clean split between platform and app team ownership. Moving to a controller that supports both, such as Traefik or Envoy Gateway, keeps both options open.

How long does migrating from ingress-nginx to a Gateway API controller usually take?

Migrating from ingress-nginx to a Gateway API controller takes days for a few simple hostnames and weeks for clusters with heavy snippet, external auth, and canary usage. The number of annotations that ingress2gateway cannot convert drives the timeline more than the number of hostnames. Plan for slippage when production owners must validate each cutover.

Romaric Philogene
About the author
Romaric Philogene

Romaric founded Qovery to make Kubernetes accessible to every engineering team. He writes about platform strategy, developer experience, and the future of cloud infrastructure.

Next step

Ship faster on infrastructure you control.

Qovery gives your team self-service deployments and managed cluster upgrades on your own AWS, GCP, Azure, or Scaleway account - or your existing Kubernetes cluster. Start deploying in under 10 minutes.