Află mai multe despre cartea lui Benny Czarny, „Cybersecurity Upside Down”

Aflați mai mult
Utilizăm inteligența artificială pentru traducerile site-urilor și, deși ne străduim să fim exacți, este posibil ca acestea să nu fie întotdeauna 100% precise. Apreciem înțelegerea dumneavoastră.

CVE-2026-9256 & CVE-2026-42945: Chaining Two NGINX Rewrite-Engine Vulnerabilities into Remote Code Execution

In-depth technical analysis of the two CVEs, conducted as part of OPSWAT Cybersecurity Fellowship Program
De Joseph Nguyen, manager de marketing de produs
Împărtășește această postare

Two recently disclosed flaws in the NGINX rewrite engine can be chained to escalate from memory corruption to unauthenticated remote code execution in a vulnerable deployment.

As part of the OPSWAT Cybersecurity Fellowship Program, our fellows, Khoi Tran and Danh Nguyen, conducted an in-depth technical analysis of CVE-2026-9256 and CVE-2026-42945, referencing the public research published by Verichains.

Both issues share a root cause: a state-management flaw in ngx_http_rewrite_module. Here’s how that flaw can be reproduced as a reliable lab demonstration of impact on nginx 1.30.0

Danh Nguyen and Khoi Tran, members of OPSWAT Cybersecurity Fellowship Program

How CVE-2026-9256 and CVE-2026-42945 Are Connected

CVE-2026-9256 and CVE-2026-42945 affect the ngx_http_rewrite_module component used by both NGINX Open Source and NGINX Plus. The vendor assigned each issue a CVSS v3.1 base score of 8.1 and classified both under CWE-122, reflecting the fact that the rewrite engine can be driven into heap memory corruption through crafted requests when a vulnerable configuration is present.

Although the two CVEs are documented separately, they share a common root cause.

CVE-2026-9256 can inflate r->args.len beyond the buffer actually allocated for the rewritten query string, creating an out-of-bounds read primitive that leaks process memory. CVE-2026-42945 leaves the same rewrite state in query-string mode for too long, causing a later copy step to write more escaped bytes than the earlier sizing pass reserved. When combined in a controlled environment, the first flaw defeats ASLR and the second redirects a cleanup handler, enabling code execution in the worker process.

Figure 1: CVSS score of the CVE on NVD

Our fellows reproduced the attack chain on Ubuntu 22.04 with glibc 2.35 and ASLR enabled. In this environment, the exploit consistently disclosed live heap and library pointers before achieving remote code execution through a forged memory-pool cleanup record. These findings demonstrate how the two vulnerabilities can be chained to achieve significantly greater impact than a typical worker-process crash.

About NGINX

NGINX is widely used as a web server, reverse proxy, and traffic-routing layer in front of APIs and applications. Its HTTP rewrite module evaluates directives like rewrite, if, and set, transforming request paths, arguments, and variables before a request reaches its destination.

These operations run inside NGINX worker processes, which use memory pools to hold request buffers and bookkeeping structures. This makes buffer sizing critical: a write past an allocated buffer can corrupt adjacent request data, and incorrect length metadata can cause later reads to go out of bounds.

Figure 2: NGINX core connections handling
Figure 3: Initial pool creation inside main
Figure 4: Memory mapping area
Figure 5: Pool Cleanup Struct

Context tehnic

The key allocator primitive is ngx_pool_t; NGINX's per-request scratch space. Small, request-scoped objects get allocated sequentially from this pool, then released together once the request finishes. It's an efficient design, but it has a side effect: adjacent objects often end up sitting close together in memory. An overflow in one buffer, as a result, can easily corrupt a neighboring structure allocated from that same pool.

The pool's cleanup list is where this gets especially dangerous. Each entry in that list stores three things: a handler, a data pointer, and a pointer to the next entry. When a request finishes, ngx_destroy_pool walks this list and invokes every registered handler in turn. So, if an attacker manages to redirect a cleanup pointer toward attacker-controlled data crafted to resemble a valid cleanup node, the consequences are severe; the worker process ends up calling an arbitrary function pointer, with attacker-chosen data as its argument.

There's a second prerequisite at play: URL escaping. Whenever the rewrite engine emits query-string data, any byte that isn't URL-safe gets expanded by ngx_escape_uri, a single input byte can balloon into three output bytes, like %2B. A mismatch between the length-calculation path and the copy path is dangerous: the copy path may need far more space than the allocator ever reserved for it.

Figure 6: Heap buffer overflow

NGINX Workflow

Under normal conditions, NGINX’s script engine builds rewritten values in two phases. The first pass computes the final length and allocates the destination buffer with ngx_pnalloc. The second pass copies data into that buffer. This pattern is safe only when both passes make identical assumptions about escaping and output size.

In the length pass for regex-based rewrites, ngx_http_script_regex_start_code accounts for the bytes that will be produced later. The corresponding copy logic, such as ngx_http_script_copy_capture_code, then writes the captures into the allocated buffer. As shown in Figures 7 through 9, the engine expects its internal is_args state to remain consistent across both passes.

Figure 7: Length calculation for the first phase
Figure 8: ngx_http_script_copy_capture_code function
Figure 9: ngx_http_script_complex_value_code function

The problem begins when a rewrite replacement string enters query-string mode by processing a ?. That transition sets e->is_args = 1, which tells later copy logic to escape characters as URL arguments. If the engine fails to clear that flag before a later directive reuses the same request-scoped execution state, the copy pass and length pass stop agreeing on how many bytes will be written.

Analiza vulnerabilității

Cauza principală

Both CVEs originate from the same state-management flaw: the request-scoped script engine can carry e->is_args across directive boundaries after entering query-string mode. The length pass runs on a fresh local engine, but the copy pass reuses shared request state. Once those two paths disagree about whether escaping is active, buffer sizing no longer matches buffer writes.

This shared root cause is visible in the upstream fix to ngx_http_script_regex_end_code, which now clears e->is_args before the engine continues. Restoring that invariant prevents both the query-string over-read used in PoolSlip and the forward heap overflow used in Rift.

Cod vulnerabil

PoolSlip (CVE-2026-9256) appears when overlapping PCRE captures are copied into a rewritten query string. In the demonstrated configuration, the regex ^/search/((.*))$ captures the same attacker-controlled substring twice, then injects both captures into the args portion of the rewritten URL. The copy path escapes both captures, but the length accounting does not budget for that expanded output correctly, so r->args.len ends up describing a region larger than the actual allocation.

Figure 10: NGINX vulnerable configuration for leak primitive

That mismatch turns a buffer-sizing bug into an information disclosure primitive. In the reproduced lab, the rewritten request is forwarded to an offline backend, which forces a fallback error page that reflects $args. Before that fallback page is rendered, NGINX allocates fresh pool objects containing live heap and library pointers. Because r->args.len now extends beyond the original args buffer, the reflected response includes adjacent heap data instead of only attacker input.

Figure 11: Pool overflow demonstration
Figure 12: Leak primitive process
Figure 13: Runtime memory map – ASLR on

Rift (CVE-2026-42945) uses the same stale is_args state differently. Here, a rewrite enters query-string mode and is followed by another rewrite, if, or set directive that reuses an unnamed capture. The length pass measures the capture as raw bytes, but the copy pass escapes it as query-string data. The result is a forward heap overflow whose size depends on how many bytes require escaping.

In the controlled reproduction, that write primitive is constrained to URL-safe bytes, so it is not used to place a full arbitrary pointer. Instead, it partially overwrites the low two bytes of the pool’s cleanup pointer while leaving the randomized high bytes intact. That is sufficient to retarget the pointer within the same 64 KB region to a sprayed fake cleanup record holding handler = &system and data = <command>.

Figure 14: Pool overwrite demonstration
Figure 15: Overwrite to adjacent pool

Exploatare

The real-world impact was validated in a controlled lab that mimics an API gateway. The deployment exposes both vulnerable rewrite patterns: a degraded search path that reflects $args, and an order-processing path whose request pool remains alive long enough for the overflow to reach the target cleanup pointer.

Figure 16: NGINX configuration

The reproduced chain unfolds in five stages:

  • First, PoolSlip leaks process memory through the reflected degraded page, revealing live heap and library pointers.
  • Second, the attacker sprays fake cleanup records into request-pool memory using request bodies that can carry arbitrary bytes.
  • Third, a victim request is groomed so its pool lands at a predictable offset with a non-NULL cleanup pointer.
  • Fourth, Rift partially overwrites the low two bytes of that pointer to redirect it into the sprayed records.
  • Finally, when the groomed request finishes, ngx_destroy_pool walks the corrupted cleanup list and invokes the forged handler(data) pair.
Figure 17: Web Application Running a Vulnerable Version of NGINX
Figure 18: Attacker Compromises the Server by Chaining NGINX Vulnerabilities

Atenuare

To mitigate CVE-2026-42945 (Rift) and CVE-2026-9256 (PoolSlip), organizations should upgrade NGINX to a version that addresses both vulnerabilities: 1.30.2 or later in the stable branch, or 1.31.1 or later in the mainline branch. Security teams should also review NGINX rewrite configurations and assess potentially exposed instances, particularly those processing untrusted HTTP requests.

Beyond patching, maintaining visibility into vulnerable software components is essential. OPSWAT MetaDefender Software Supply Chain helps organizations identify software components and known vulnerabilities through Software Bills of Materials (SBOMs) and vulnerability analysis. By analyzing application dependencies and container images, security teams can identify potentially affected NGINX components, assess their exposure, and prioritize remediation to reduce software supply chain risks.

Referințe

Rămâneți la curent cu OPSWAT!

Înscrieți-vă astăzi pentru a primi cele mai recente actualizări ale companiei, povești, informații despre evenimente și multe altele.