CVE-2026-42945: The 18-Year-Old NGINX RCE Nobody Caught
On May 13, 2026, F5 published an advisory for CVE-2026-42945 — a heap buffer overflow in NGINX’s ngx_http_rewrite_module that has existed since version 0.6.27, released in 2008.
That is 18 years of silent exposure. Every NGINX instance running rewrite rules with set directives has been carrying this bug. A public proof-of-concept achieving unauthenticated remote code execution is already on GitHub.
CVSS: 9.2 Critical.
The Bug: Two-Pass Memory Mismatch
NGINX’s internal script engine processes directives in two passes:
- Length pass — calculates how much memory to allocate
- Copy pass — writes data into the allocated buffer
The vulnerability is a state mismatch between these two passes.
When a rewrite directive contains a question mark (?), it permanently sets an internal flag: is_args = 1 on the main script engine. This flag changes how URI characters are handled — specifically, it triggers ngx_escape_uri to expand certain bytes from 1 byte to 3 bytes (percent-encoding).
Here is the problem:
- During the length pass, NGINX uses a zeroed-out sub-engine where
is_args = 0. It calculates buffer size without accounting for percent-encoding expansion. - During the copy pass, the main engine runs with
is_args = 1.ngx_escape_uriexpands escapable bytes to 3x their size.
Result: more data is written than allocated. Classic heap buffer overflow.
Length pass: is_args=0 → calculates N bytes needed
Copy pass: is_args=1 → writes N + (2 × escapable_bytes) → overflow
Why This Matters
This is not a theoretical overflow. The researchers at depthfirst achieved reliable, repeatable code execution by chaining:
- Heap manipulation through controlled request patterns
- Fake cleanup structure spraying via POST bodies
- Exploitation of NGINX’s deterministic multi-process architecture
The deterministic nature of NGINX’s process model is key — it makes heap layout predictable, which turns a probabilistic overflow into a reliable exploit. The PoC works on systems with ASLR disabled; with ASLR enabled, exploitation becomes harder but not impossible given the deterministic process architecture.
Trigger Conditions
The configuration pattern that activates this vulnerability is common:
server {
location /api {
set $backend "upstream";
rewrite ^/api/(.*)\?(.*)$ /v2/$1?$2 break;
proxy_pass http://$backend;
}
}
Any configuration combining rewrite (with a ? in the pattern or replacement) and set directives is potentially vulnerable. This is a standard pattern in API gateways, reverse proxies, and URL normalization setups.
Affected Versions
Everything from 2008 to the patch:
| Product | Affected | Patched |
|---|---|---|
| NGINX Open Source | 0.6.27 – 1.30.0 | 1.30.1 / 1.31.0 |
| NGINX Plus | R32 – R36 | R36 P1 / R37 |
| NGINX Instance Manager | 2.16.0 – 2.21.1 | 2.21.2 |
| NGINX Ingress Controller | 3.5.0 – 5.4.1 | 3.7.3 / 4.0.2 / 5.4.2 |
| NGINX Gateway Fabric | 1.3.0 – 2.5.1 | 1.6.3 / 2.5.2 |
| F5 WAF for NGINX | 5.9.0 – 5.12.1 | 5.12.2 |
Why Nobody Caught It for 18 Years
This bug is invisible to pattern-matching static analysis. Here is why:
The overflow depends on runtime state. The
is_argsflag is set by prior directive execution, not by the code at the overflow site. No single function is “wrong” in isolation.The two-pass pattern is correct by design. It is a legitimate optimization — calculate size, allocate, write. The bug is that two different execution contexts calculate vs. write.
The trigger requires specific config combinations. Not every NGINX instance uses
rewrite+settogether with?in the pattern. Fuzzing with default configs would never hit this path.Code auditors focus on the copy path. If you audit
ngx_escape_uri, it is doing exactly what it should — encoding correctly. The bug is upstream: the length calculation used different assumptions.The two-pass pattern exists everywhere. This is not an NGINX-specific design. Any system that separates size calculation from data writing — serializers, protocol encoders, template engines — carries this same class of risk. The question is whether the two passes share identical state assumptions. In NGINX, they did not.
This is the class of vulnerability that AI-driven code scanning (like the new AWS Security Agent) claims to detect — bugs that require understanding trust boundaries, data flows, and state across multiple execution contexts. Whether those tools would actually catch this specific instance is a different question. The bug requires tracing a flag set in one directive’s execution through to a different directive’s memory allocation — that is multi-step state reasoning, not pattern matching.
Immediate Actions
If you run NGINX (you probably do):
- Check your version:
nginx -v - If below 1.30.1: update now
- Audit your configs for the vulnerable pattern:
# Find rewrite directives with ? in the same server/location block as set
grep -rn "rewrite" /etc/nginx/ | grep "?"
grep -rn "set \$" /etc/nginx/
If both appear in the same server or location block: you are in the vulnerable path.
If you cannot patch immediately:
- Place an additional WAF layer in front of affected NGINX instances
- Restrict external access to paths using rewrite + set patterns
- Monitor for anomalous POST body sizes (exploit uses POST for heap spraying)
The Broader Lesson
Eighteen years. Millions of deployments. Countless code audits. And a critical RCE sat in one of the most reviewed open-source projects in existence.
The bug was not hiding in obscure code. ngx_http_rewrite_module is core functionality. The issue is that the vulnerability spans two execution contexts — it does not exist in any single function. You have to understand the state machine to see it.
This is exactly the kind of bug that justifies architectural security review over pattern-matching SAST. Tools that reason about state, data flow, and execution context will catch what grep never can.
Patch your NGINX. Then think about what else might be hiding in your two-pass implementations.
If you found this analysis useful, you might also like Harness Engineering: 6 Defense Layers I Built Around Claude Code — how I protect AI agent systems from exactly this class of state-mismatch vulnerability.