Quick answer
CVE-2026-42945, nicknamed NGINX Rift, is a heap buffer overflow in nginx's rewrite module that went unnoticed for eighteen years. It is triggered when a rewrite directive whose replacement contains a question mark is followed by a rewrite, if or set directive that reads an unnamed capture such as $1, so nginx sizes the buffer without escaping but then writes the capture with escaping applied. It affects nginx 0.6.27 to 1.30.0 and is fixed in 1.31.0 and 1.30.1.
At a glance
critical severity- Identifier
- CVE-2026-42945
- Also known as
- NGINX Rift
- Product
- nginx (open source and NGINX Plus) and F5 NGINX products
- Affected
- nginx open source 0.6.27 – 1.30.0; NGINX Plus R32 – R36; Other F5 products built on nginx, e.g. NGINX Ingress Controller and Gateway Fabric (see F5 advisory)
- Fixed in
- nginx 1.31.0 (mainline); nginx 1.30.1 (stable); NGINX Plus R36 P4, R32 P6, PLS.37.0.0.1
- CVSS
- 8.1 (CVSS 3.1) / 9.2 (CVSS 4.0), per F5
- Disclosed
- Known exploited (CISA KEV)
- Not listed
Patch available since May 2026. Public proofs of concept. Exploitation attempts reported from 16 May 2026; not listed in CISA KEV as of 24 October 2026.
01What is CVE-2026-42945?
CVE-2026-42945 is a heap buffer overflow in nginx's HTTP rewrite module. An unauthenticated attacker can send a crafted request URI that causes the worker process to write past a heap allocation. The immediate result is a worker crash and restart; on systems where address space layout randomisation (ASLR) is disabled or can be bypassed, the vendor and the original researchers describe remote code execution as possible.
The flaw was discovered by the research firm depthfirst, which reported it to the nginx team at F5 on 21 April 2026 and named it NGINX Rift. F5 published a coordinated advisory on 13 May 2026. The underlying bug was introduced in 2008 (nginx 0.6.27), so it sat in the code for roughly eighteen years before disclosure.
It is a data-plane issue in the request-handling path. It is reachable over plain HTTP without authentication, which is what raises its severity, but it only fires when the configuration matches a specific and non-default pattern.
02Who is affected, and under what configuration?
Open source nginx from 0.6.27 through 1.30.0 is vulnerable. F5 also lists NGINX Plus R32 through R36 and other F5 products built on the same engine, such as NGINX Ingress Controller and NGINX Gateway Fabric; the F5 advisory has the full product list. If you run a product that embeds nginx, treat it as affected until the vendor says otherwise.
Being on an affected version is necessary but not sufficient. Exposure also requires the vulnerable directive shape. The upstream fix commit documents the minimal reproducer below, which captures the two ingredients: a question mark in the rewrite replacement, and a later directive that reads an unnamed capture.
- A rewrite replacement that contains a question mark (it starts a query string)
- A following rewrite, if or set directive in the same context
- An unnamed capture reference such as $1 or $2 in that following directive
- An affected nginx version (open source 0.6.27 to 1.30.0, or a listed F5 product)
location / {
rewrite ^(.*) /new?c=1; # '?' sets the internal is_args flag
set $myvar $1; # reads an unnamed capture afterwards
return 200 $myvar;
}03How does the overflow happen?
nginx compiles rewrite and set directives into a small script programme that runs in two passes. The first pass measures how many bytes the result will need and allocates exactly that much from the request pool. The second pass copies the data in. The design is fast because it allocates once, but it is only safe if the two passes agree on the length.
When a rewrite replacement contains a question mark, nginx sets an internal flag meaning "what follows is a query string". In the affected code that flag was never cleared. The length pass ran on a freshly zeroed sub-engine where the flag was unset, so it measured a capture as raw bytes. The copy pass ran on the main engine where the flag was still set, so it re-escaped the same capture as a query-string argument, expanding characters such as plus, percent and ampersand. The copy therefore wrote more bytes than were allocated, and the surplus landed outside the buffer.
Because the overflowing bytes come from the attacker's URI, the corruption is shaped by the attacker rather than random. Repeated requests also keep workers in a crash-and-restart loop, which is a denial of service in its own right even where code execution is not achievable.
04How do I check whether I am affected?
Two checks matter: your version, and your configuration. Confirm the running version first, then audit the full merged configuration rather than individual files, because the dangerous combination can be split across an include.
# 1. version and distro package
nginx -v
dpkg -l | grep -E '^ii\s+nginx' # Debian/Ubuntu
# 2. dump the full merged config, then audit it
nginx -T 2>/dev/null > /tmp/nginx-full.conf
# rewrite replacements that contain a '?'
grep -nE '^\s*rewrite\s+\S+\s+[^ ;]*\?' /tmp/nginx-full.conf
# set/if/rewrite directives that read an unnamed capture
grep -nE '^\s*(set|if|rewrite)\b.*\$[1-9]' /tmp/nginx-full.conf05How do I fix or mitigate it?
The fix is to upgrade. Open source nginx 1.31.0 (mainline) and 1.30.1 (stable) contain the patched code; restart nginx after upgrading so workers reload the new binary. NGINX Plus users should move to R36 P4 or R32 P6, or to the PLS.37 release line, which shipped with the fix; the NGINX Plus release notes list no patch for R33 to R35. The upstream patch is a one-line change that resets the query-string flag at the end of each rewrite, so later directives measure and copy captures the same way. General bounds checks on script copies only arrived later, in nginx 1.31.3 and 1.30.4.
Distribution packages carry the fix under their own version numbers. On Debian it landed in nginx 1.22.1-9+deb12u7 for bookworm (DSA-6278-1) and 1.26.3-3+deb13u5 for trixie; on Ubuntu, 1.24.0-2ubuntu7.8 for noble and 1.18.0-6ubuntu14.11 for jammy (USN-8271-1). Match the package version, not the upstream number; why an old nginx/1.18.0 banner is usually already patched explains the difference.
If you genuinely cannot upgrade immediately, remove the trigger: wherever a directive after a rewrite with a question mark reads $1 or $2, capture the value with a named group instead and read the name. Named captures are stored as ordinary variables and do not go through the vulnerable escaping path.
# vulnerable shape: '?' in the replacement, then $1 read by a later directive
rewrite ^/old/(.*)$ /new?from=old;
set $orig_path $1;
# mitigated: the later directive reads a named capture
rewrite ^/old/(?<old_path>.*)$ /new?from=old;
set $orig_path $old_path;06What can a WAF or reverse proxy do about it?
Be honest about the limits here. CVE-2026-42945 is a bug in nginx's own request processing, so if your vulnerable nginx is the thing terminating the request, no filter running inside that same nginx can reliably save it. The corruption happens during the rewrite phase, early and inside the worker.
Where an upstream proxy genuinely helps is as a separate tier. If a patched reverse proxy terminates connections and forwards clean, normalised requests to an origin, the origin's exposure is reduced, and the crash-loop denial-of-service angle is absorbed the same way any HTTP flood is. A proxy can also drop obviously malformed URIs. What it cannot do is turn an unpatched origin into a safe one, which is why edge filtering is a supplement to patching, never a replacement; what virtual patching can and cannot do sets out that boundary. A reverse proxy such as GuardX absorbs flood traffic before it reaches the origin, but the origin still has to be patched.
For the wider playbook on keeping an origin reachable under attack, see how to stop a DDoS attack and what a web application firewall is.
| Measure | Stops crash/DoS? | Stops code execution? |
|---|---|---|
| Upgrade nginx to 1.31.0 / 1.30.1 | Yes | Yes |
| Named captures instead of $1/$2 | Yes (removes trigger) | Yes (removes trigger) |
| Separate patched reverse proxy in front | Helps, not guaranteed | No, if origin unpatched |
| ASLR enabled on the host | No | Raises the bar only |
| Blocking individual source IPs | No | No |
08Timeline
| Date | Event |
|---|---|
| 18 Apr 2026 | depthfirst's automated analysis flags the rewrite overflow |
| 21 Apr 2026 | Reported to the nginx team via a GitHub security advisory |
| 22 Apr 2026 | Upstream fix authored (published with the release on 13 May) |
| 13 May 2026 | F5 advisory and depthfirst write-up; nginx 1.31.0 / 1.30.1 and NGINX Plus R36 P4 / R32 P6 released |
| 16 May 2026 | VulnCheck reports exploitation attempts against its honeypots |
| 22 May 2026 | Follow-up CVE-2026-9256 fixed in 1.31.1 / 1.30.2 |
Questions
Frequently asked questions
Sources
Sources and verification
Vulnerable and mitigated rewrite patterns loaded into nginx 1.22.1 with nginx -t, and the audit greps checked with GNU grep 3.8, on Debian 12, October 2026.
- 01NVD — CVE-2026-42945 · NVD
- 02nginx security advisories · nginx.org
- 03F5 advisory K000161019 · F5
- 04NGINX Rift: achieving nginx RCE via an 18-year-old vulnerability · depthfirst
- 05nginx fix commit 524977e (rewrite escaping / buffer overrun) · nginx GitHub
- 06Debian security tracker — CVE-2026-42945 · Debian
- 07Ubuntu — CVE-2026-42945 · Ubuntu
- 08NGINX Plus release notes · F5 NGINX docs
- 09Attackers are exploiting critical NGINX vulnerability (CVE-2026-42945) · Help Net Security
Last updated