Share
## 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.