NGINX Rift: How Scary Is It Really?
When depthfirst published their writeup on CVE-2026-42945, they demonstrated a heap buffer overflow in nginx’s rewrite module that leads to remote code execution. The natural question: how many real-world configs are actually vulnerable?
After building a pre-patch nginx and crash-testing configurations from dozens of popular open-source projects, the answer is: surprisingly few.
The Vulnerability in 30 Seconds
nginx’s rewrite module uses two passes when processing URI captures: a length calculation pass and a copy pass. Each pass uses a separate “engine” struct. The length engine is zeroed with ngx_memzero():
ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); // le.is_args = 0
When a rewrite contains ? in the replacement string, it sets e->is_args = 1 on the main engine. Before the patch, this flag wasn’t cleared between directives. A subsequent set $var $1 creates a fresh zeroed sub-engine — length pass skips URI escaping (le.is_args = 0), copy pass applies it (e->is_args = 1). Each + becomes %2B: 1 byte allocated, 3 bytes written.
The Trigger Pattern
The depthfirst PoC uses:
location ~ ^/api/(.*)$ {
rewrite ^/api/(.*)$ /internal?migrated=true;
set $original_endpoint $1;
}
Two directives. The rewrite sets is_args, the set triggers the mismatch. I confirmed this crashes with double free or corruption (!prev) and signal 6 against commit 98fc3bb78 (pre-patch).
What About Single Rewrites?
This is the pattern I expected to be dangerous:
rewrite ^/secure/(.*)$ /login?redirect=$1;
One directive, ? in the replacement, capture in the replacement. It’s the most common pattern involving query strings and captures. It also appears in Magento 2 (12k stars):
rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last;
Result: no crash. Within a single rewrite, mark_args_code sets le.is_args = 1 during the length pass too. Both engines agree. No mismatch, no overflow.
What About break/last with Captures?
This is the kubernetes/ingress-nginx (19k stars) pattern, generated for every rewrite-target annotation:
rewrite "(?i)/prefix(/|$)(.*)" /$2 break;
And this is from blakeblackshear/frigate (32k stars):
rewrite ^/frigate-api/(.*)$ /$1 break;
No crash. No ? in the replacement means is_args is never set.
The Comprehensive Test
I pulled nginx configs from a dozen popular open-source projects and crash-tested each against the pre-patch build. The patterns fall into three categories:
rewrite /$capture break; + proxy_pass — the reverse proxy pattern. Strip a prefix, pass the rest to a backend. Used by Dify, Open WebUI, Stirling-PDF, PocketBase, Private-GPT, Frigate, Glances, Security Onion, NGINX Demos, and generated by kubernetes/ingress-nginx for every rewrite-target annotation. No ? in the replacement, no crash.
rewrite ... $capture last; — internal redirect with captures. Magento 2’s rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last; is the most interesting variant here — it has ? and captures, but it’s a single directive. Safe.
rewrite $1/mp3/$2.mp3 break; — the nginx.org docs example. Multiple captures, break flag. No ?, no crash.
Zero crashes across all 12 configs. Every real-world pattern I found uses a single rewrite directive. The vulnerable two-directive pattern (rewrite ? followed by set $var $capture) doesn’t appear in any of them.
What Actually Crashes
Only patterns combining rewrite ? with a subsequent set $var $1. The specific variation doesn’t matter — whether the set is followed by return, used in string interpolation, or stands alone, every variant I tested crashed with signal 6.
Everything else: safe.
The Patch
One line added in ngx_http_script_regex_end_code():
e->is_args = 0; // Added by patch
e->quote = 0; // Already existed pre-patch
So How Scary Is It?
The vulnerability is real and the exploitation is impressive — depthfirst’s technique of spraying fake ngx_pool_cleanup_t structures via POST bodies to hijack the cleanup handler chain is clever work.
But the trigger condition is narrow: you need rewrite with ? in the replacement followed by a set (or similar) that evaluates captures. In practice:
- Single rewrites (even with
?and captures): safe - break/last with captures: safe
- redirect/permanent: safe
- kubernetes/ingress-nginx rewrite-target: safe
- Every real-world config I tested: safe
I couldn’t find a single real-world configuration on GitHub matching the vulnerable pattern outside of PoC repos. That doesn’t mean they don’t exist — but they’re rare enough that a broad GitHub search across millions of nginx configs came up empty.
If you use nginx, you should still upgrade. The pattern could appear in private configurations, and the RCE is pre-auth. But if you’re triaging urgency: check whether any of your location blocks have a rewrite with ? in the replacement followed by a set that uses $1 or $2. If not, you have time.