AI-Powered Cyberattacks: How to Detect, Prevent & Defend Against Intelligent Threats

Read Now
We utilize artificial intelligence for site translations, and while we strive for accuracy, they may not always be 100% precise. Your understanding is appreciated.

IngressNightmare: CVE-2025-1974 Remote Code Execution Vulnerability & Remediation

by OPSWAT
Share this Post

May 2025 marked the public disclosure of a critical security vulnerability, CVE-2025-1974, dubbed IngressNightmare, affecting the Kubernetes ingress-nginx controller widely deployed across cloud native infrastructures. This vulnerability allows unauthenticated attackers to inject arbitrary configurations into NGINX, potentially leading to unauthorized RCE (remote code execution) and full cluster compromise.

As part of the OPSWAT Fellowship program, our fellows conducted an in-depth technical analysis to better understand its root cause, exploitation path, and mitigation strategies surrounding this high-severity issue.

Overview of CVE-2025-1974 

CVE-2025-1974 is a critical template injection vulnerability identified in ingress-nginx versions up to 1.11.4 and specifically 1.12.0. Attackers with node-level access to a Kubernetes cluster can exploit this flaw to execute arbitrary code using RCE via the ingress-nginx controller which, by default, has extensive privileges, including access to critical secrets within the cluster.

The Kubernetes Security Response Committee assigned this vulnerability with a CVSS v3.1 score of 9.8 (critical severity):

CVSS metrics UI for CVE-2025-1974 showing exploitability and impact options for IngressNightmare

Key Components in this Analysis

Kubernetes Overview

Kubernetes (K8s) is an open-source platform for automating deployment, scaling, and operational management of containerized applications. Kubernetes clusters typically consist of multiple machines, which can include both physical hardware and virtual machines, working collectively to provide highly available, scalable, and manageable application environments.

NGINX Ingress Controller

NGINX ingress controller (ingress-nginx) is an open-source ingress controller built on top of the NGINX web server. It operates within a Kubernetes cluster, functioning primarily as a reverse proxy and load balancer. This controller interprets Ingress resources defined by users and translates them into actionable NGINX configurations to route traffic flow into and within the cluster.

AdmissionReview and Its Role

Ingress-nginx integrates with Kubernetes using a webhook service called AdmissionReview. This service is crucial for processing native Kubernetes Ingress objects and translating them into validated and syntactically correct NGINX configurations. While AdmissionReview ensures configuration accuracy, it operates independently of the ingress-nginx controller and generally lacks stringent authentication controls. This lack of strict authentication is a key factor that contributed to the exploitability of CVE-2025-1974.

CVE-2025-1974 (IngressNightmare) diagram showing AdmissionReview in Kubernetes Ingress NGINX controller workflow

Vulnerability Exploitation and Technical Analysis

Exploitation Mechanism

At its core, the exploitation of CVE-2025-1974 starts with a malicious request. Attackers craft a malicious request to the AdmissionReview webhook, forcing NGINX to dynamically load a shared library at runtime. Based on this mechanism, our fellows analyzed both the AdmissionReview webhook and the NGINX workflow to understand this exploit path.

CVE-2025-1974 (IngressNightmare) diagram showing Kubernetes exploit path via malicious ingress object and NGINX

Template Injection Vulnerability

On AdmissionReview webhook, when processing incoming requests, the CheckIngress function transforms Kubernetes Ingress Objects into valid NGINX configuration files. The flow proceeds as follows:

Go code snippet showing template injection logic related to CVE-2025-1974 (IngressNightmare) vulnerability
  1. Each configuration is parsed and passed to generateTemplate to be formatted according to predefined NGINX templates.
  2. Subsequently, testTemplate validates the generated configuration against the underlying NGINX binary.

All NGINX configurations are based on predefined templates found in the nginx.tmpl file within the ingress-nginx source code:

Code snippet showing template injection vulnerability related to CVE-2025-1974 (IngressNightmare)

Within the generateTemplate function, the configuration is processed as shown in the following code snippet:

Go code snippet showing annotation parsing logic related to CVE-2025-1974 (IngressNightmare) template injection

However, input validation and sanitization are insufficient. Specifically, the uid field from an Ingress Object is directly inserted into the NGINX configuration template, creating an injection point. An attacker can exploit this by supplying crafted input such as uid="1234#;\n\n}\n}\n}\n injection_value".

This malicious input allows global scope injection into the NGINX template, enabling attackers to trigger arbitrary NGINX directives and potentially achieve RCE.

Nginx config code showing template injection related to CVE-2025-1974 (IngressNightmare) vulnerability

From Template Injection to Remote Code Execution

The testTemplate() Function Explained

After the NGINX configuration is generated by the generateTemplate function, the testTemplate function creates a temporary configuration file and runs the NGINX library with the command nginx -c {config_file} -t. This forces the NGINX binary to parse and validate the configuration.

Go code for testTemplate() function and interfaces related to CVE-2025-1974 (IngressNightmare) vulnerability

To exploit the vulnerability, an attacker needs to identify a directive capable of executing malicious code. Initially, our fellows identified the load_module directive as potentially useful, because this directive allows NGINX to load external plugins. However, this directive is only permitted in the early phase of configuration parsing, which does not match our injection point.

Code screenshot showing load_module syntax and context, relevant to CVE-2025-1974 (IngressNightmare)
Terminal output showing nginx config test failure related to CVE-2025-1974 (IngressNightmare) load_module error

To solve this challenge, we continued further research, which led to the ssl_engine directive, described as "The module may be dynamically loaded by OpenSSL during configuration testing." This raised curiosity due to its capability to dynamically load modules, necessitating a deeper examination.

Code screenshot explaining ssl_engine device syntax for CVE-2025-1974 (IngressNightmare) context

Understanding the ssl_engine Directive

To gain a deeper understanding of how NGINX handles the ssl_engine directive, as well as determining the conditions under which NGINX permits dynamic loading of additional modules via this directive, we looked into the NGINX source code.

C code snippet showing NGINX configuration parsing, relevant to CVE-2025-1974 (IngressNightmare) ssl_engine directive

On startup, NGINX loads its initial state, then parses configuration files line by line. Each directive is handled by the nginx_command_t structure, with the directive ssl_engine directly invoking the ngx_openssl_commands.

C struct definition for ngx_command_s related to CVE-2025-1974 (IngressNightmare) ssl_engine directive
Figure 1. ngx_command_s definition
Code snippet showing ssl_engine directive array, relevant to CVE-2025-1974 (IngressNightmare) context
Figure 2 ssl_engine ngx_command_t structure

Upon analyzing the ngx_openssl_commands function, our fellows discovered that it relies on OpenSSL support, specifically the function ENGINE_by_id which is used for hardware-accelerated SSL modules.

C code snippet showing ssl_engine directive logic, relevant to CVE-2025-1974 (IngressNightmare) analysis

And while analyzing the ENGINE_by_id function, we determined that it enables the dynamic loading of shared libraries. Moreover, if the library is compiled with the __attribute__((constructor)) extension, the associated function can be executed immediately upon loading. This indicates that by exploiting the ssl_engine directive, an attacker could load arbitrary shared libraries on the host, potentially leading to RCE.

Targeting Shared Libraries and Attack Strategy

To reliably facilitate code execution, the next step involves identifying a shared library. Rather than relying on external libraries, a more viable and controlled approach emerges from NGINX’s own behavior: the client body buffer mechanism. This feature enables NGINX to offload large incoming requests into temporary files, opening opportunities for exploitation based on predictable file handling behavior.

nginx.conf code showing temp paths and buffer settings, relevant to CVE-2025-1974 (IngressNightmare) attack

By default, when an incoming request exceeds 8KB, NGINX writes the request body to a temporary file located at /tmp/nginx/client-body, using a filename in the format cfg-{random_value}. These temporary files are retained for up to 60 seconds between successful chunks of a received message.

CVE-2025-1974 (IngressNightmare) diagram showing attack flow targeting NGINX shared libraries and temp files

After writing a partial request body to a temporary file, NGINX defers deletion until the entire body is received. If the request remains incomplete and no data is received for up to 60 seconds, the file is eventually purged. However, by intentionally withholding the final chunk of data, an attacker can keep the temporary file in use, making it exploitable.

Diagram showing CVE-2025-1974 (IngressNightmare) attack flow targeting NGINX shared libraries and file deletion

Although the uploaded file content can be controlled, locating it on the file system is difficult due to the randomized filename. The storage path can be configured using client_body_temp_path, but the filename is randomly generated at runtime, making it unpredictable. This randomness significantly hinders targeted access even through brute force. To overcome this, the team leveraged behaviors inherent to the Linux OS. Consider the following example:

Python code exploiting CVE-2025-1974 (IngressNightmare) with file write and infinite loop logic

This code opens a file and keeps it in an active state, closely mimicking the behavior of NGINX's client body buffer mechanism. Using /proc/{pid}/fd directory, attackers can find symbolic links created by the Linux kernel that map open file descriptors to their corresponding file paths. This route allows attackers to reduce the brute-force space to only two variables: the process ID (pid) and the file descriptor (fd).

Terminal output showing process and file descriptor details relevant to CVE-2025-1974 (IngressNightmare) attack strategy

Simulating Exploitation

Based on the analysis above, a practical exploitation approach for RCE within the Ingress-NGINX pod is:

  1. Upload a malicious shared library using NGINX's client body buffer mechanism to store it temporarily on the file system.
  2. Use template injection to initiate a brute force attempt that forces NGINX to load the previously uploaded shared library via vulnerable directives.
VE-2025-1974 (IngressNightmare) exploitation flow diagram showing attack path through Ingress-NGINX to NGINX

Crafting the Payload Containing the Shared Library

To ensure code execution upon loading, an entrypoint function with constructor extension is defined within the malicious shared library. This function is executed upon loading by NGINX and is designed to establish a reverse shell connection to a remote host. 

C code for CVE-2025-1974 (IngressNightmare) payload crafting with shared library and reverse shell command

After compilation, the size of the resulting shared library comfortably exceeded 8KB, allowing it to be buffered by NGINX without requiring additional padding.

Terminal listing showing danger.so shared library for CVE-2025-1974 (IngressNightmare) payload creation

Our fellows then crafted a request with an inflated Content-Length value (e.g., 1MB) to introduce a size mismatch. This caused NGINX to buffer the entire body rather than processing it immediately, ensuring the shared object would be written to a predictable location.

Go code for crafting a payload with shared library, related to CVE-2025-1974 (IngressNightmare) exploit

Triggering the Shared Library Through Injection

With the shared library in place, we next injected a malicious directive into the NGINX configuration using the vulnerable uid field. This directive included ssl_engine pointing to the buffered file path:

JSON code showing Kubernetes Ingress object with injection for CVE-2025-1974 (IngressNightmare) exploit

Successful RCE requires the ssl_engine directive to reference the correct path to the buffered file. This can be achieved via an automated brute force script that systematically iterates over possible combinations of process IDs and file descriptors to identify the valid symbolic link pointing to the buffered shared object.

Go code exploiting CVE-2025-1974 (IngressNightmare) via shared library injection and webhook validation

Below is a sample of the generated NGINX template that triggered the exploit.

Nginx config code showing CVE-2025-1974 (IngressNightmare) injection via ssl_engine and mirror directives

Upon successful exploitation, the attacker could gain shell access under the context of the ingress-nginx pod, which by default had access to sensitive Kubernetes cluster secrets.

Terminal output showing kubectl get secrets -A command, relevant to CVE-2025-1974 (IngressNightmare)

Mitigation and Remediation

To effectively mitigate the risks associated with CVE-2025-1974, organizations require a solution that provides visibility and control over their open-source components.

OPSWAT SBOM, a foundational technology within the MetaDefender® platform, addresses this need by providing an inventory of all software components, libraries, Docker containers, and dependencies in use. It allows organizations to track, secure, and update their components proactively.

UI screenshot showing CVE-2025-1974 (IngressNightmare) critical vulnerability in nginx-ingress-controller

In the example above, the SBOM technology in MetaDefender Core™ scanned the nginx-ingress-controller package that contained the CVE-2025-1974 vulnerability. The system automatically flagged the issue as Critical and provided guidance on fixed versions available, enabling teams to quickly prioritize and patch the vulnerability before it can be exploited.

OPSWAT SBOM is available in MetaDefender Core and MetaDefender Software Supply Chain™, enabling security teams to identify and act on vulnerabilities faster. With OPSWAT SBOM, security teams can:

  • Quickly locate vulnerable components - Immediately identify the open-source components affected by deserialization attacks. This ensures swift action in either patching or replacing the vulnerable libraries. 
  • Ensure proactive patching and updates - Continuously monitor open-source components through OPSWAT SBOM to stay ahead of deserialization vulnerabilities. OPSWAT SBOM can detect outdated or insecure components, enabling timely updates and reduced exposure to attacks. 
  • Maintain compliance and reporting – OPSWAT SBOM helps organizations meet compliance requirements as regulatory frameworks increasingly mandate transparency in software supply chains.

Stay Up-to-Date With OPSWAT!

Sign up today to receive the latest company updates, stories, event info, and more.