This is a loaded trapdoor that only opens if your rewrite rules were built in exactly the wrong shape
CVE-2026-9256 is a heap-based buffer overflow in NGINX ngx_http_rewrite_module triggered when a rewrite directive combines *overlapping PCRE captures* with a replacement string that references multiple captures in a redirect or arguments context. Upstream marks Open Source NGINX 0.1.17 through 1.31.0 as vulnerable and 1.31.1+ / 1.30.2+ as fixed; the same bug also affects corresponding NGINX Plus builds, with vendor-fixed releases at R32 P7, R36 P5, and 37.0.1.1.
The vendor's HIGH rating is technically understandable because the bug is unauthenticated and sits on the data plane, but it overshoots most enterprise reality. The decisive friction is *configuration specificity*: an attacker only gets leverage if your live config contains the exact rewrite pattern shape, and even then the common result on modern Linux is worker crash/restart, while true RCE needs ASLR disabled or a separate ASLR bypass.
4 steps from start to impact.
Find an exposed NGINX edge with vulnerable code
1.31.0 or 1.30.1. Commodity recon tools like httpx or nmap can fingerprint banners, but version data alone is not enough because exploitability depends on the deployed rewrite rules, not just the binary.- Unauthenticated remote network access to the HTTP service
- Target is running vulnerable NGINX Open Source or NGINX Plus code
- Banner suppression or reverse-proxy layering does not fully hide the product
- Many enterprise deployments suppress exact version strings
- A vulnerable binary is not exploitable unless the live config uses the dangerous rewrite pattern
- Some fleets terminate traffic on another edge before requests ever reach the affected NGINX tier
Reach a location that executes the bad rewrite
location whose rewrite rule uses overlapping captures and multiple backreferences in a redirect or query-string context. The commit for 3f135ae shows the failing pattern class directly, and a simple curl-style request is enough once the right route is found.- A matching
rewritedirective exists in the active config - The regex contains overlapping captures such as nested groups
- The replacement string references multiple captures such as
$1$2
- This is a narrow config shape, not a default NGINX behavior
- Many rewrite rules are generated from templates and may not use overlapping captures at all
- Attackers usually need some path discovery or source leakage to find the affected route
nginx -T plus static pattern matching for nested capture groups and multi-backreference replacements.Trigger heap corruption in a worker
- Request reaches the vulnerable rewrite path
- The vulnerable code path is exercised in redirect or args handling
- Worker process handles the request before rate limits or upstream blocks intervene
- Worker isolation limits blast radius compared with a monolithic daemon crash
- Auto-restart behavior can turn single-shot exploitation into noisy instability instead of durable compromise
- Rate limiting, CDN shielding, and upstream proxying can reduce request delivery volume
worker process restarts, segfaults, core dumps, elevated 5xx on specific URIs, and correlated bursts of malformed requests in NGINX access/error logs.Turn memory corruption into code execution
- ASLR is disabled, weakened, or bypassed
- The attacker can shape memory reliably enough for control
- Process-level mitigations do not break exploitation
- Modern Linux servers usually have ASLR enabled by default
- Memory-corruption reliability across heterogeneous fleets is hard
- EDR, crash collection, and service watchdogs raise noise during repeated attempts
The supporting signals.
| In-the-wild status | No confirmed exploitation found in primary sources reviewed. The CISA KEV catalog does not list CVE-2026-9256 as of this assessment. |
|---|---|
| Proof-of-concept availability | No mature public exploit repo located in primary sources. However, the upstream fix commit and Openwall disclosure provide enough detail for a competent operator to build a crash PoC quickly. |
| EPSS | 0.00076 from the user-supplied intel block — extremely low, consistent with a bug that is reachable from the network but gated by a narrow configuration prerequisite. |
| KEV status | Not KEV-listed. No published KEV due date, no CISA exploitation designation, and no primary-source campaign reporting located. |
| CVSS and what it misses | Vendor/CNA scores it 8.1 HIGH with CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H; NVD also shows a CNA-supplied CVSS v4.0 9.2. The miss is that CVSS treats the attack as network-exploitable but does not meaningfully model the *specific rewrite-rule shape* required in live configs. |
| Affected versions | Upstream NGINX security advisories mark Open Source 0.1.17-1.31.0 as vulnerable. Corresponding NGINX Plus trains are covered by the vendor advisory referenced by NVD. |
| Fixed versions and backports | Upstream fixes are 1.31.1+ and 1.30.2+; NGINX Plus fixed builds are R32 P7, R36 P5, and 37.0.1.1 per vendor-linked advisories. Downstream examples: Ubuntu lists fixed package backports across supported LTS releases, and OpenResty 1.29.2.5 backports the patch. |
| Researcher / reporting | The NGINX CHANGES entry credits Mufeed VH of Winfunc Research. The fix commit also documents the triggering configuration examples. |
| Disclosure timeline | Disclosed 2026-05-22. NVD shows publication on May 22, 2026, and upstream released 1.31.1 and 1.30.2 the same day. |
| Scanning / exposure reality | Exposure is likely broad at the product level but narrow at the exploitable-path level. Public internet scanners can find lots of NGINX, but none of the primary sources reviewed provide GreyNoise/Shodan/Censys evidence that the exact vulnerable rewrite pattern is being mass-scanned or broadly fingerprinted. Treat internet-facing NGINX as the population; treat the dangerous rewrite shape as the true exploitable subset. |
noisgate verdict.
The single biggest downward pressure is that exploitation requires a *very specific live rewrite-rule pattern*, not merely a vulnerable NGINX version on the internet. On modern hardened Linux, the most common practical outcome is worker crash/restart rather than reliable remote code execution, and there is no primary-source evidence of active exploitation.
Why this verdict
- Downgraded for config-specific reachability: the attacker needs a narrow
rewritepattern with overlapping captures plus multiple backreferences; most NGINX installs will not meet that prerequisite. - Downgraded for exploitation reliability: vendor text itself conditions code execution on ASLR being disabled or bypassed, which cuts against broad internet-scale RCE in modern fleets.
- Upward pressure remains because it is unauthenticated and edge-facing: if the bad rewrite exists on a public route, the attacker does not need credentials or user interaction to hit it.
- No exploitation pressure today: no KEV listing, no primary-source campaign reporting, and the user-supplied EPSS is extremely low.
- Worker-process blast radius is usually bounded: the common operational failure mode is a worker restart or crash, which matters for availability but is not the same as durable host takeover.
Why not higher?
This is not a straight-line unauthenticated RCE against every exposed NGINX server. A vulnerable binary is only part of the story; the exploit path also needs a precise rewrite configuration shape and, for the worst-case outcome, weak or bypassed memory-randomization defenses.
Why not lower?
The bug still lives in a public request-processing path on one of the most widely deployed edge servers in enterprise estates. If your config does contain the bad rewrite pattern, an unauthenticated remote party can trigger memory corruption with no foothold, so this is not backlog trivia.
What to do — in priority order.
- Audit live rewrite rules — Run
nginx -Tacross internet-facing NGINX and search for nested capture groups combined with multiple backreferences inrewritereplacements, especially redirects and query-string rewrites. For a MEDIUM finding there is no mitigation SLA — go straight to the 365-day remediation window, but this audit should happen in the next normal engineering cycle because it determines whether the bug is actually reachable in your fleet. - Prefer simple rewrites or non-capturing groups — Where business logic allows, replace overlapping capture designs with simpler regex or non-capturing groups so that a vulnerable version loses the dangerous trigger condition. There is no mitigation SLA for this bucket, so treat it as a normal-change hardening task while you work through patching.
- Keep ASLR fully enabled — Validate
kernel.randomize_va_space=2and avoid local hardening exceptions that weaken user-space randomization. This does not remove the bug, but it materially degrades the path from crash to code execution; for MEDIUM, do it in ordinary platform hygiene work rather than as an emergency change. - Watch for worker crash patterns — Alert on NGINX worker restarts, segfaults, coredumps, and URI-specific 5xx spikes so you can distinguish opportunistic fuzzing from normal traffic anomalies. This is the most useful near-term detective control when version-only asset data cannot tell you whether the vulnerable rewrite exists.
- A generic WAF signature does not solve this well; the trigger is tied to your server-side rewrite logic, not a stable payload pattern with one clean IOC.
- Version-only scanning is necessary but insufficient; it tells you which binaries are old, not whether the dangerous rewrite shape is present.
- 'No control plane exposure' reasoning is irrelevant; the vendor explicitly states this is a *data plane* issue, so management-plane isolation does not reduce exploitability.
- ASLR alone is not a fix; it mainly suppresses the RCE path, but the crash/DoS path still exists on vulnerable and reachable configs.
Crowdsourced verification payload.
Run this on the target NGINX host or inside the container image that actually serves traffic. Invoke it as sudo bash ./check-cve-2026-9256.sh because it needs nginx -v and ideally nginx -T access to the loaded config; it prints PATCHED, VULNERABLE, or UNKNOWN and exits 0, 1, or 2 respectively.
#!/usr/bin/env bash
# check-cve-2026-9256.sh
# Detect likely exposure to CVE-2026-9256 (NGINX ngx_http_rewrite_module overlapping captures)
# Exit codes:
# 0 = PATCHED
# 1 = VULNERABLE
# 2 = UNKNOWN
set -u
patched_mainline_min="1.31.1"
patched_stable_min="1.30.2"
mainline_floor="1.31.0"
have_cmd() { command -v "$1" >/dev/null 2>&1; }
ver_ge() {
# returns 0 if $1 >= $2
[ "$(printf '%s\n%s\n' "$2" "$1" | sort -V | head -n1)" = "$2" ]
}
ver_lt() {
# returns 0 if $1 < $2
! ver_ge "$1" "$2"
}
extract_version() {
local raw
raw="$(nginx -v 2>&1)" || return 1
printf '%s' "$raw" | sed -n 's#.*nginx/\([0-9][0-9.]*\).*#\1#p'
}
if ! have_cmd nginx; then
echo "UNKNOWN: nginx binary not found in PATH"
exit 2
fi
version="$(extract_version)"
if [ -z "${version:-}" ]; then
echo "UNKNOWN: could not parse nginx version"
exit 2
fi
# Patched version logic:
# - mainline fixed at 1.31.1+
# - stable fixed at 1.30.2+ and < 1.31.0
if ver_ge "$version" "$patched_mainline_min"; then
echo "PATCHED: nginx version $version is >= $patched_mainline_min"
exit 0
fi
if ver_ge "$version" "$patched_stable_min" && ver_lt "$version" "$mainline_floor"; then
echo "PATCHED: nginx version $version is in the fixed stable range >= $patched_stable_min and < $mainline_floor"
exit 0
fi
# Vulnerable code train. Now check whether config appears to contain the risky rewrite pattern.
config_dump="$(nginx -T 2>&1)"
nginx_t_rc=$?
if [ $nginx_t_rc -ne 0 ] || [ -z "$config_dump" ]; then
echo "UNKNOWN: nginx version $version is vulnerable-by-version, but 'nginx -T' could not be read"
exit 2
fi
# Heuristic checks only. We look for rewrite lines with:
# - nested capture groups like ((...))
# - multiple backreferences in replacement like $1$2
# - redirect or query-string usage, which upstream says are relevant contexts
suspicious_lines="$(printf '%s\n' "$config_dump" | awk '
BEGIN { IGNORECASE=1 }
/^[[:space:]]*rewrite[[:space:]]+/ {
line=$0
nested = (line ~ /\(\([^)]*\*[^)]*\)\)/ || line ~ /\(\(.*\)\)/)
multibackref = (line ~ /\$[0-9].*\$[0-9]/)
redirectish = (line ~ /redirect[[:space:]]*;/ || line ~ /\?.*\$[0-9]/)
if (nested && multibackref && redirectish) print line
}
')"
if [ -n "$suspicious_lines" ]; then
echo "VULNERABLE: nginx version $version is vulnerable and suspicious rewrite directives were found"
printf '%s\n' "$suspicious_lines" | sed 's/^/MATCH: /'
exit 1
fi
echo "UNKNOWN: nginx version $version is vulnerable-by-version, but no obvious matching rewrite directives were found by heuristic scan"
exit 2
If you remember one thing.
rewrite rules, because that prerequisite is what separates noise from real exposure here. For this MEDIUM assessment there is noisgate mitigation SLA: no mitigation SLA — go straight to the 365-day remediation window; use that window to move exposed systems to 1.31.1+, 1.30.2+, or the corresponding Plus fixed release, while prioritizing public-facing hosts with suspicious rewrite patterns first under the noisgate remediation SLA.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.