← Blog

CVE-2026-42945: The 18-Year-Old NGINX RCE Nobody Caught

· 5 min read · ES

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:

  1. Length pass — calculates how much memory to allocate
  2. 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_uri expands 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:

  1. Heap manipulation through controlled request patterns
  2. Fake cleanup structure spraying via POST bodies
  3. 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:

ProductAffectedPatched
NGINX Open Source0.6.27 – 1.30.01.30.1 / 1.31.0
NGINX PlusR32 – R36R36 P1 / R37
NGINX Instance Manager2.16.0 – 2.21.12.21.2
NGINX Ingress Controller3.5.0 – 5.4.13.7.3 / 4.0.2 / 5.4.2
NGINX Gateway Fabric1.3.0 – 2.5.11.6.3 / 2.5.2
F5 WAF for NGINX5.9.0 – 5.12.15.12.2

Why Nobody Caught It for 18 Years

This bug is invisible to pattern-matching static analysis. Here is why:

  1. The overflow depends on runtime state. The is_args flag is set by prior directive execution, not by the code at the overflow site. No single function is “wrong” in isolation.

  2. 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.

  3. The trigger requires specific config combinations. Not every NGINX instance uses rewrite + set together with ? in the pattern. Fuzzing with default configs would never hit this path.

  4. 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.

  5. 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):

  1. Check your version: nginx -v
  2. If below 1.30.1: update now
  3. 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.