## https://sploitus.com/exploit?id=48470061-EC55-50C0-8274-090AE01AF1AD
# ingress-nginx CVE-2026-42945 backport kit
This repository documents a defensive backport workflow for teams running
`ingress-nginx` controller images that still bundle an NGINX version affected by
CVE-2026-42945.
It is not an official NGINX or Kubernetes ingress-nginx release. Treat it as an
emergency mitigation pattern you can inspect, rebuild, and validate while you
wait for an official fixed controller image that fits your environment.
## What This Addresses
CVE-2026-42945 affects NGINX `ngx_http_rewrite_module`. The risky shape is an
NGINX configuration where:
1. a `rewrite` replacement contains a `?`,
2. a later `rewrite`, `if`, or `set` directive runs in the same script path, and
3. that later directive copies an unnamed PCRE capture such as `$1` or `$2`.
The upstream fix clears stale query-string escaping state before subsequent
script operations process captures:
```diff
+ e->is_args = 0;
e->quote = 0;
```
The included patch applies this fix to NGINX 1.25.5, which is the NGINX version
bundled by several older ingress-nginx controller lines.
## Why Backport Instead of Bump
For plain `nginx` containers, upgrading to a fixed NGINX release is usually the
right answer.
For ingress-nginx, a full NGINX bump may not be immediately safe because the
controller image includes NGINX modules, Lua/OpenResty integration, dynamic
modules, templates, and ingress-nginx-specific build patches. A focused backport
lets you keep the same controller and module ABI while remediating the root
cause.
## Repository Layout
```text
.
โโโ Dockerfile
โโโ patches/
โ โโโ nginx-1.25.5-CVE-2026-42945.patch
โโโ scripts/
โ โโโ local-validation.sh
โ โโโ verify-image.sh
โโโ docs/
โ โโโ backporting-other-nginx-versions.md
โ โโโ linkedin-post-draft.md
โโโ .github/workflows/build.yml
```
## Quick Start
Build a patched image for an ingress-nginx controller base:
```shell
docker buildx build --platform linux/amd64 \
--build-arg UPSTREAM_CONTROLLER_IMAGE='registry.k8s.io/ingress-nginx/controller:v1.11.5@sha256:a1cbad75b0a7098bf9325132794dddf9eef917e8a7fe246749a4cea7ff6f01eb' \
--build-arg UPSTREAM_CONTROLLER_TAG='controller-v1.11.5' \
-t 'ghcr.io/YOUR_GITHUB_USER/ingress-nginx-controller:cve-2026-42945-v1.11.5' \
--load \
.
```
Verify the image:
```shell
scripts/verify-image.sh \
'ghcr.io/YOUR_GITHUB_USER/ingress-nginx-controller:cve-2026-42945-v1.11.5' \
'1.25.5'
```
Publish with GitHub Actions by running the `Build patched ingress-nginx image`
workflow manually, or by pushing a tag such as:
```text
v1.11.5-cve-2026-42945
```
The workflow publishes to GitHub Container Registry:
```text
ghcr.io//:
```
## Critical Image Layering Detail
Do not replace all of `/etc/nginx` in the final ingress-nginx controller image.
The upstream controller image contains bootstrap config, Lua code, and templates
that the controller expects at runtime.
This Dockerfile intentionally preserves that controller-owned content and copies
only the rebuilt runtime/module pieces:
```dockerfile
COPY --from=patched-nginx-rootfs /etc/nginx/modules /etc/nginx/modules
COPY --from=patched-nginx-rootfs /etc/nginx/modsecurity /etc/nginx/modsecurity
COPY --from=patched-nginx-rootfs /etc/nginx/owasp-modsecurity-crs /etc/nginx/owasp-modsecurity-crs
```
Replacing all of `/etc/nginx` can cause the controller to start without a valid
NGINX master process, leaving `/tmp/nginx/nginx.pid` empty and creating reload
loops.
## Kubernetes Rollout Example
Prefer deploying by digest, even if you also keep a human-readable tag:
```yaml
controller:
image:
registry: ghcr.io
image: YOUR_GITHUB_USER/ingress-nginx-controller
tag: cve-2026-42945-v1.11.5
digest: sha256:
```
This avoids kubelet cache surprises when rebuilding the same tag with
`imagePullPolicy: IfNotPresent`.
Check rollout:
```shell
kubectl get ds -A -l app.kubernetes.io/name=ingress-nginx \
-o custom-columns='NAMESPACE:.metadata.namespace,IMAGE:.spec.template.spec.containers[0].image,READY:.status.numberReady,DESIRED:.status.desiredNumberScheduled,UPDATED:.status.updatedNumberScheduled'
kubectl get pods -A -l app.kubernetes.io/name=ingress-nginx \
-o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{" "}{.status.containerStatuses[0].imageID}{"\n"}{end}'
```
## Validation
Run the local regression helper only against local containers:
```shell
scripts/local-validation.sh \
'nginx:1.25.5-alpine' \
'ghcr.io/YOUR_GITHUB_USER/ingress-nginx-controller:cve-2026-42945-v1.11.5'
```
Expected result:
- the vulnerable baseline can show worker crashes with the controlled trigger
config,
- the patched image remains stable,
- no `signal 11`, `segfault`, or exited-on-signal log lines appear for the
patched image.
Do not run crash-oriented tests against third-party or production systems unless
you own them and have explicit authorization.
## Backporting Other NGINX Versions
See [`docs/backporting-other-nginx-versions.md`](docs/backporting-other-nginx-versions.md).
In short:
1. download the exact NGINX source used by your controller image,
2. apply the patch with `patch --dry-run`,
3. if context differs, inspect `ngx_http_script_regex_end_code` and add the same
`e->is_args = 0;` reset immediately before `e->quote = 0;`,
4. rebuild using your ingress-nginx source tag and original controller image,
5. validate locally before rollout.
## Scanner Caveat
This is a backport. `nginx -V` and `nginx -v` can still report the old NGINX
version. Version-only scanners may continue to flag the image unless they
understand patch provenance.
Keep evidence with every release:
- source controller image and digest,
- ingress-nginx source tag,
- patch checksum,
- built image digest,
- CI logs,
- validation output.
## Responsible Use
This repository is for defensive remediation and validation. It deliberately
does not provide instructions for attacking public systems.
## License
This repository's original content is released under the MIT License. NGINX,
ingress-nginx, and bundled third-party components remain under their respective
licenses.