The Uncomfortable Truth
NGINX Rift matters because the vulnerable code path sits below your Kubernetes abstraction. The Ingress object, the annotation, the Helm chart, and the controller are only the delivery chain. The dangerous instruction is executed later by the NGINX worker process inside the native rewrite engine.
The bug lives insrc/http/ngx_http_script.c, inside the native C implementation used byngx_http_rewrite_module. It is not Lua. It is not the ingress-nginx Go controller. It is not an annotation parser issue.
The public NGINX Rift repository describes CVE-2026-42945 as a heap buffer overflow in ngx_http_rewrite_module affecting configurations that use rewrite and set directives. The same public write-up states that NGINX Open Source versions 0.6.27 through 1.30.0 are affected and that 1.30.1 / 1.31.0 contain fixes.
Where the Bug Actually Lives
The vulnerable path is inside NGINX’s script engine. NGINX processes rewrite logic in two conceptual phases: first it calculates how large the output buffer must be; then it copies transformed URI data into that buffer.
$1.? behavior and escapes URI bytes differently.That mismatch is the important engineering lesson. The vulnerable state is not “NGINX exists.” The vulnerable state is “a vulnerable NGINX binary executes a rewrite configuration shape that triggers inconsistent buffer sizing and copy behavior.”
When You Are Affected
0.6.27–1.30.0 or vulnerable NGINX Plus builds.nginx.conf contains rewrite logic using unnamed captures such as $1 or $2.?rewrite, if, or set in the same context.When You Are Probably Not Affected
| State | Risk | Reason |
|---|---|---|
NGINX 1.30.1+ stable or 1.31.0+ mainline | Low | Fixed according to NGINX advisory data. |
No rewrite directives in rendered config | Low | The vulnerable module path is not exercised by that config. |
Named captures instead of $1/$2 | Lower | Configuration mitigation guidance points to replacing unnamed captures. |
| Lua rewrite logic only | Not this bug | Lua rewrite code is not the vulnerable native C ngx_http_rewrite_module path. |
| ASLR enabled | Reduces RCE reliability, not a fix | ASLR can make exploitation harder; it does not remove overflow or DoS risk. |
Commands: Check Your Kubernetes Context
kubectl get pods -A \ -l app.kubernetes.io/name=ingress-nginx \ -o wide
NS=$(kubectl get pods -A -l app.kubernetes.io/name=ingress-nginx \
-o jsonpath='{.items[0].metadata.namespace}')
POD=$(kubectl -n "$NS" get pods -l app.kubernetes.io/component=controller \
-o jsonpath='{.items[0].metadata.name}')
echo "namespace=$NS pod=$POD"kubectl -n "$NS" exec "$POD" -c controller -- nginx -v kubectl -n "$NS" exec "$POD" -c controller -- nginx -V 2>&1 | tr ' ' '\n' | egrep 'nginx/|rewrite|lua|pcre|http_rewrite'
kubectl -n "$NS" exec "$POD" -c controller -- nginx -T > nginx-rendered.conf 2>&1 grep -nE 'rewrite[[:space:]].*\$[0-9]+.*\?' nginx-rendered.conf grep -nE 'rewrite[[:space:]].*\$[0-9]+.*\?' nginx-rendered.conf | cut -d: -f1 | while read n; do sed -n "$((n-5)),$((n+8))p" nginx-rendered.conf echo "-----" done
kubectl get ingress -A -o json | jq -r '
.items[]
| select(
(.metadata.annotations["nginx.ingress.kubernetes.io/rewrite-target"] // "" | test("\\$[0-9]")) or
(.metadata.annotations["nginx.ingress.kubernetes.io/use-regex"] // "" | ascii_downcase == "true") or
(.metadata.annotations["nginx.ingress.kubernetes.io/configuration-snippet"] // "" | test("rewrite|set|if")) or
(.metadata.annotations["nginx.ingress.kubernetes.io/server-snippet"] // "" | test("rewrite|set|if"))
)
| [.metadata.namespace, .metadata.name,
(.metadata.annotations["nginx.ingress.kubernetes.io/use-regex"] // "-"),
(.metadata.annotations["nginx.ingress.kubernetes.io/rewrite-target"] // "-")]
| @tsv'kubectl -n "$NS" get configmap -l app.kubernetes.io/component=controller -o yaml \ | egrep -n 'allow-snippet-annotations|annotations-risk-level|enable-annotation-validation|strict-validate-path-type'
Kubernetes Configuration That Creates Risk
The danger is not the annotation alone. The danger is the generated NGINX directive chain.
metadata:
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: "/backend/$1?tenant=$2"
spec:
rules:
- http:
paths:
- path: /api/(.*)/(.*)
pathType: ImplementationSpecificIf that input produces a rendered rewrite directive with unnamed capture variables and a ? in the replacement, treat it as vulnerable until version and final rendered config prove otherwise.
Mitigation Path
| Priority | Action | Why |
|---|---|---|
| 1 | Upgrade NGINX to 1.30.1+ or 1.31.0+ | Removes the native rewrite engine bug. |
| 2 | Replace unnamed captures $1, $2 with named captures | Configuration-level mitigation when immediate patching is blocked. |
| 3 | Disable snippets unless explicitly required | Prevents raw user-supplied NGINX directives from entering config. |
| 4 | Block risky rewrite-target patterns at admission | Stops recurrence through Ingress changes. |
| 5 | Keep ASLR enabled | Reduces exploit reliability but does not fix the bug. |
Kyverno Admission Mitigation
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: block-nginx-rift-rewrite-patterns
spec:
validationFailureAction: Enforce
background: true
rules:
- name: block-rewrite-target-unnamed-capture-query
match:
any:
- resources:
kinds:
- networking.k8s.io/v1/Ingress
validate:
message: "NGINX Rift mitigation: rewrite-target must not combine $1/$2 with '?'."
deny:
conditions:
any:
- key: "{{ regex_match('.*\\\\$[0-9]+.*\\\\?.*', request.object.metadata.annotations.\\"nginx.ingress.kubernetes.io/rewrite-target\\" || '') }}"
operator: Equals
value: true
- key: "{{ regex_match('.*\\\\?.*\\\\$[0-9]+.*', request.object.metadata.annotations.\\"nginx.ingress.kubernetes.io/rewrite-target\\" || '') }}"
operator: Equals
value: true
- name: block-raw-snippet-rewrite-unnamed-capture-query
match:
any:
- resources:
kinds:
- networking.k8s.io/v1/Ingress
validate:
message: "NGINX Rift mitigation: snippets must not define rewrite directives with unnamed captures and '?'."
deny:
conditions:
any:
- key: "{{ regex_match('(?s).*rewrite\\\\s+.*\\\\$[0-9]+.*\\\\?.*', request.object.metadata.annotations.\\"nginx.ingress.kubernetes.io/configuration-snippet\\" || '') }}"
operator: Equals
value: true
- key: "{{ regex_match('(?s).*rewrite\\\\s+.*\\\\$[0-9]+.*\\\\?.*', request.object.metadata.annotations.\\"nginx.ingress.kubernetes.io/server-snippet\\" || '') }}"
operator: Equals
value: trueRuntime Signals to Watch
Final Word
Do not reduce this vulnerability to “upgrade ingress-nginx.” The real exposure question is sharper: which NGINX binary is inside the controller image, and what exact NGINX configuration did the Kubernetes controller render from your Ingress objects?
My view: every Kubernetes platform team should audit the generated nginx.conf, not only the Ingress YAML. The YAML is intent. The rendered NGINX configuration is what actually executes.
— Riad DAHMANI, k8sec.io
Find dangerous ingress patterns before they become attack paths.
K8SEC correlates Kubernetes objects, generated exposure, RBAC, and runtime signals so defenders can see exploitable paths before attackers do.
Explore K8SEC