needhelp
← Back to blog

NGINX Rift (CVE-2026-42945): An 18-Year-Old Heap Overflow in the Rewrite Module

by xingwangzhe
NGINX
CVE
Security
RCE
Heap Overflow
Web Server

NGINX Rift (CVE-2026-42945, CVSS 9.2): A critical heap buffer overflow in NGINX’s rewrite module, autonomously discovered by depthfirst’s AI analysis system. Introduced in 2008 and impacting 18 years of NGINX releases, it lets an unauthenticated attacker achieve remote code execution with a single crafted HTTP request.


The Vulnerability That Was Hiding in Plain Sight

On May 13, 2026, F5 and depthfirst jointly disclosed CVE-2026-42945 — a critical heap buffer overflow in the ngx_http_rewrite_module of NGINX. The vulnerability had been sitting in the codebase since 2008, introduced in NGINX 0.6.27, affecting every subsequent version up to 1.30.0.

What makes this discovery particularly remarkable is how it was found: not by a human researcher manually auditing code, but by depthfirst’s autonomous vulnerability analysis system. The AI system was pointed at the NGINX source code, and within six hours it flagged the heap overflow issue that had evaded human detection for 18 years.

MetricValue
CVECVE-2026-42945
CVSS v4.09.2 (Critical)
Discovered bydepthfirst (autonomous AI analysis)
Introduced2008 (NGINX 0.6.27)
Lurked for18 years
Vulnerability typeHeap buffer overflow (two-pass length mismatch)
Authentication requiredNone
ImpactRemote Code Execution (RCE) or worker crash (DoS)
Fix versionNGINX 1.31.0 / 1.30.1

Affected Versions

The vulnerability spans nearly every NGINX product line:

ProductAffected Versions
NGINX Open Source0.6.27 through 1.30.0
NGINX PlusR32 through R36
NGINX Instance Manager2.16.0 through 2.21.1
F5 NGINX App Protect WAF4.9.0–4.16.0, 5.1.0–5.8.0
NGINX Ingress Controller3.5.0–3.7.2, 4.0.0–4.0.1, 5.0.0–5.4.1
NGINX Gateway Fabric1.3.0–1.6.2, 2.0.0–2.5.1

Given that NGINX powers approximately one-third of all websites globally, the blast radius of this vulnerability is enormous.


Technical Deep Dive

The Two-Pass Design

To understand the bug, you need to understand NGINX’s script engine. When NGINX evaluates a rewrite or set directive, it operates in two passes:

  1. Length pass (ngx_http_script_len_code): Calculates the total buffer size needed to hold the final output
  2. Copy pass (ngx_http_script_run / ngx_http_script_copy_code): Allocates a buffer of that size and writes the actual data

The contract is simple: pass 1 tells you exactly how many bytes to allocate, pass 2 writes exactly that many bytes. If the two disagree — you get a heap overflow.

Root Cause: The Orphaned is_args Flag

The vulnerability lives in src/http/ngx_http_script.c. When a rewrite directive’s replacement string contains a question mark (?), the function ngx_http_script_start_args_code sets a flag on the script engine:

e->is_args = 1;

This flag signals that subsequent URI components should be treated as query arguments and URI-escaped (e.g., +%2B, &%26).

The problem: this flag is never reset. It remains set on the main script engine (e) for the remainder of the request processing.

The Mismatch

When a subsequent set directive references a regex capture group (e.g., $1), the script engine evaluates it. During the length pass, ngx_http_script_complex_value_code creates a fresh, zeroed sub-engine (le):

ngx_http_script_len_code_ctx_t  le;
ngx_memzero(&le, sizeof(ngx_http_script_len_code_ctx_t));

Since le.ip and le.is_args are both zero, the length-computation function ngx_http_script_copy_capture_len_code takes the else branch — it returns the raw, unescaped capture length.

During the copy pass, the code runs on the main engine (e), where e->is_args is still 1. The copy function ngx_http_script_copy_capture_code enters a different branch:

if (e->is_args) {
    // Escapes the URI: expands + % & from 1 byte to 3 bytes
    n = ngx_escape_uri(NULL, src, len, NGX_ESCAPE_ARGS);
    // ...allocates and writes escaped version
}

Every escapable character in the attacker-controlled URI (+, %, &) expands from 1 byte to 3 bytes. The buffer was sized for the raw (unescaped) length — the write runs past the allocation.

// Length pass measures:  raw_len bytes
// Copy pass writes:       raw_len + 2*N bytes  (where N = escapable chars)
//                           ↑↑↑  HEAP OVERFLOW

This is a classic two-pass contract violation, made possible because the is_args state was set by a completely unrelated rewrite directive and never cleaned up.

Exploitation

The researchers at depthfirst developed a working proof-of-concept demonstrating unauthenticated RCE against NGINX with ASLR disabled. The key properties that make exploitation practical:

PropertyDetail
Overflow sizeFully attacker-controlled (number of +, &, % in URI)
Overflow dataAttacker-controlled (escaped URI content)
ReproducibilityDeterministic — same request always overflows the same way
Retry budgetInfinite — crashed workers respawn with identical heap layout
AuthenticationNone required — reachable from public internet

The infinite retry budget is particularly important for ASLR bypass. Modern exploitation against ASLR typically requires information leakage or brute-forcing. Because NGINX spawns replacement workers with an identical heap layout after each crash, an attacker can make unlimited attempts at no cost.

The researchers describe a theoretical technique: by progressively overwriting pointer bytes across repeated requests, an attacker can redirect execution flow to a controlled payload, defeating ASLR without an explicit information leak step.


Trigger Condition: Are You Affected?

The vulnerability is only reachable if your NGINX configuration contains a specific pattern:

# Vulnerable pattern:
# 1. A rewrite with ? in replacement AND unnamed capture groups
# 2. Followed by another rewrite, if, or set in the same scope

rewrite ^/users/([0-9]+)/profile/(.*)$ /profile.php?id=$1&tab=$2 last;

The ? in /profile.php?id=$1&tab=$2 sets is_args = 1. The unnamed captures $1, $2 trigger the vulnerable code path when a subsequent directive evaluates them.

Check Your Configuration

grep -rn 'rewrite.*\?.*\$[0-9]' /etc/nginx/

If this returns any matches, your configuration is affected.


Mitigation

Immediate: Upgrade

VersionAction
NGINX Open SourceUpgrade to 1.31.0 or 1.30.1
NGINX Plus R36Apply R36 P4
NGINX Plus R32Apply R32 P6

Workaround: Named Capture Groups

If you cannot upgrade immediately, replace unnamed captures with named captures in every affected rewrite directive:

# Vulnerable — unnamed captures with ? in replacement
rewrite ^/users/([0-9]+)/profile/(.*)$ /profile.php?id=$1&tab=$2 last;

# Mitigated — named captures bypass the vulnerable code path
rewrite ^/users/(?<user_id>[0-9]+)/profile/(?<section>.*)$ /profile.php?id=$user_id&tab=$section last;

Named captures ((?<name>...)) do not pass through the vulnerable escaping logic, because the ngx_http_script_copy_capture_code function only applies URI escaping to unnamed captures. This configuration change removes the attack surface without a binary upgrade.

Verify the Fix

# Check version
nginx -v

# After upgrade, verify: should be 1.31.0 or 1.30.1+
nginx -v 2>&1 | grep -E '1\.31\.0|1\.30\.[1-9]'

Timeline

DateEvent
2008Vulnerability introduced in NGINX 0.6.27 (commit initializing rewrite module)
2026-04depthfirst autonomous system scans NGINX source, flags heap overflow within 6 hours
2026-04-24F5 confirms the issue and coordinates disclosure
2026-05-13F5 releases NGINX 1.31.0 / 1.30.1 with fix; CVE-2026-42945 published
2026-05-14This article published

Broader Implications: AI-Discovered Vulnerabilities

CVE-2026-42945 is notable not just for its severity, but for how it was discovered. An autonomous AI system found a bug in a codebase that has been audited by thousands of engineers, security researchers, and open source contributors over 18 years — in six hours.

This follows a pattern we’ve seen accelerating in 2026:

VulnerabilityDiscovered byTime to find
Copy Fail (Linux kernel LPE)Xint Code (AI)~1 hour
Dirty Frag (Linux kernel LPE)Human (Hyunwoo Kim)Manual audit
CVE-2026-42945 (NGINX Rift)depthfirst (Autonomous AI)6 hours
CVE-2026-42946 (NGINX overread)depthfirst (Autonomous AI)Same scan

The gap between what a determined AI system can find and what human reviewers have historically caught is growing rapidly. For maintainers of critical infrastructure, this means:

  1. Assume there are more undiscovered bugs in your dependencies — the ones found so far are just what the current generation of AI tools can catch
  2. Minimize attack surface — remove unused modules, disable unnecessary features, use the principle of least functionality
  3. Defense in depth — even if a component is compromised, other layers should limit the blast radius

NGINX itself is an interesting case: it’s known for its clean codebase and strong security track record. And yet, an 18-year-old critical RCE was hiding in plain sight. If NGINX isn’t safe from this class of bug, no C codebase is.


Conclusion

CVE-2026-42945 (NGINX Rift) is a critical heap overflow in one of the most widely deployed software projects on the internet. It requires no authentication, can be triggered from the public internet, and gives an attacker full code execution in the NGINX worker process.

If you run NGINX, assume you are affected — unless you’ve verified your configuration doesn’t contain the vulnerable rewrite pattern, or you’ve upgraded to 1.31.0 / 1.30.1.

The 18-year lifespan of this bug is a stark reminder: our infrastructure is held together by code that has never been comprehensively audited by modern tools. The AI era of vulnerability discovery is just beginning, and we should expect more revelations like this — not fewer.


References


Infographics

NGINX Rift Heap Overflow Diagram

Figure 1: NGINX Rift — how the two-pass buffer length mismatch produces a heap overflow

Share this page