NGINX Rift (CVE-2026-42945): An 18-Year-Old Heap Overflow in the Rewrite Module
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.
| Metric | Value |
|---|---|
| CVE | CVE-2026-42945 |
| CVSS v4.0 | 9.2 (Critical) |
| Discovered by | depthfirst (autonomous AI analysis) |
| Introduced | 2008 (NGINX 0.6.27) |
| Lurked for | 18 years |
| Vulnerability type | Heap buffer overflow (two-pass length mismatch) |
| Authentication required | None |
| Impact | Remote Code Execution (RCE) or worker crash (DoS) |
| Fix version | NGINX 1.31.0 / 1.30.1 |
Affected Versions
The vulnerability spans nearly every NGINX product line:
| Product | Affected Versions |
|---|---|
| NGINX Open Source | 0.6.27 through 1.30.0 |
| NGINX Plus | R32 through R36 |
| NGINX Instance Manager | 2.16.0 through 2.21.1 |
| F5 NGINX App Protect WAF | 4.9.0–4.16.0, 5.1.0–5.8.0 |
| NGINX Ingress Controller | 3.5.0–3.7.2, 4.0.0–4.0.1, 5.0.0–5.4.1 |
| NGINX Gateway Fabric | 1.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:
- Length pass (
ngx_http_script_len_code): Calculates the total buffer size needed to hold the final output - 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:
| Property | Detail |
|---|---|
| Overflow size | Fully attacker-controlled (number of +, &, % in URI) |
| Overflow data | Attacker-controlled (escaped URI content) |
| Reproducibility | Deterministic — same request always overflows the same way |
| Retry budget | Infinite — crashed workers respawn with identical heap layout |
| Authentication | None 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
| Version | Action |
|---|---|
| NGINX Open Source | Upgrade to 1.31.0 or 1.30.1 |
| NGINX Plus R36 | Apply R36 P4 |
| NGINX Plus R32 | Apply 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
| Date | Event |
|---|---|
| 2008 | Vulnerability introduced in NGINX 0.6.27 (commit initializing rewrite module) |
| 2026-04 | depthfirst autonomous system scans NGINX source, flags heap overflow within 6 hours |
| 2026-04-24 | F5 confirms the issue and coordinates disclosure |
| 2026-05-13 | F5 releases NGINX 1.31.0 / 1.30.1 with fix; CVE-2026-42945 published |
| 2026-05-14 | This 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:
| Vulnerability | Discovered by | Time 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:
- 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
- Minimize attack surface — remove unused modules, disable unnecessary features, use the principle of least functionality
- 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
- depthfirst NGINX Rift Research: https://depthfirst.com/research/nginx-rift-achieving-nginx-rce-via-an-18-year-old-vulnerability
- depthfirst Landing Page: https://depthfirst.com/nginx-rift
- F5 Security Advisory K000161019: https://my.f5.com/manage/s/article/K000161019
- NGINX Security Advisories: https://nginx.org/en/security_advisories.html
- NGINX Changelog (1.31.0): https://nginx.org/en/CHANGES
Infographics
Figure 1: NGINX Rift — how the two-pass buffer length mismatch produces a heap overflow