CVE-2026-42945: rewrite directive failure mode
The nginx rewrite module can end up writing past the end of a heap buffer when is_args goes stale during rewrite processing. Crafted URIs with escapable characters are enough to push the length pass and copy pass out of sync, which is the sort of bug that turns a routing rule into a crash. In the worst case, heap corruption opens the door to remote code execution.
Where the rewrite path goes wrong in practice
The failure shows up in rewrite rules that mix a replacement string containing ? with set or if, then reference capture groups. That combination is awkward because the module has to calculate output size, then rebuild the URI with escapes applied, and both steps need to agree on the final length.
Once is_args keeps the wrong state, the sizing pass can assume one layout while the copy pass emits another. The result is an undersized heap allocation followed by a write that carries on past the buffer boundary. Worker process crashes are the obvious outcome. Heap spray changes the shape of the mess, not the fact of it.
Why stale is_args turns into heap corruption
The bug sits in the gap between “how much space do I need?” and “how much did I actually write?”. In normal rewrite handling, those two answers should match. Here they do not, because the state that tracks whether a ? needs to be treated as the argument separator is left stale.
Escaping makes the mismatch worse. A URI that looks short in its raw form can grow once characters are escaped during the rewrite. If the length pass does not account for that growth, the heap allocation comes back too small. The copy pass then writes the escaped form into that space and corrupts adjacent memory.
The length pass and copy pass stop agreeing
This is the core failure mode. The module counts one version of the data, then copies another. That is bad enough in a stack buffer; on the heap it tends to be nastier, because nearby metadata or application data can be trampled as the write runs on.
The practical trigger is not exotic. A rewrite chain with captures, a conditional, and a query marker in the replacement string gives enough moving parts for the state to drift. Once the module thinks is_args has already been dealt with, the later copy step can inherit the wrong size assumptions.
ngx_http_script_copy_capture_code() writes past the buffer
ngx_http_script_copy_capture_code() is where the mismatch becomes memory corruption. It copies captured content into the destination buffer after the size check has already been made. If that check was based on stale state, the function writes escaped data into a buffer that was never large enough for it.
That is a plain heap buffer overflow, not a subtle logic quirk. The buffer ends up too small, the copy keeps going, and the overwrite lands wherever the allocator placed the next chunk. At that point, the best outcome is a dead worker.
What to change on live systems before the next scan
If vulnerable rewrite directives are still present, the site stays exposed even with traffic filtering in place. The immediate job is to remove the rule shape that triggers the bug, then move the build to a fixed release.
Remove risky rewrite directives that mix ?, set, if, and capture groups
Search for rewrite rules that place ? in the replacement string and then chain into set or if while using capture groups. Those are the patterns that deserve attention first. They are not all broken on their own, but they are the ones that line up with the stale is_args path.
A blunt control is better than a clever one here. If a rule can be simplified without capture reuse or chained conditionals, do that. If it cannot be simplified, isolate it and test it with crafted input that includes escapable characters. Broken rewrite logic is usually very obedient right up until it is not.
Upgrade to nginx 1.30.1 and verify the fix in place
Upgrade to nginx 1.30.1 or later. That is the clean fix for CVE-2026-42945, and it removes the stale-state bug rather than asking the configuration to behave itself forever.
After the upgrade, verify the running version on every host and check the deployed config for leftover rewrite patterns that still match the failure mode. Old config paired with a new binary is a classic way to keep the trouble alive. The worker process does not care that the change looked sensible in review.




