Vulnerabilities

8 min readUpdated

CVE-2026-42945: the NGINX Rift rewrite overflow

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)
The vulnerable pattern (from the upstream fix commit)
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.

Version and configuration audit
# 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.conf

05How 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.

Config-level mitigation when you cannot patch yet
# 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.

MeasureStops crash/DoS?Stops code execution?
Upgrade nginx to 1.31.0 / 1.30.1YesYes
Named captures instead of $1/$2Yes (removes trigger)Yes (removes trigger)
Separate patched reverse proxy in frontHelps, not guaranteedNo, if origin unpatched
ASLR enabled on the hostNoRaises the bar only
Blocking individual source IPsNoNo

08Timeline

DateEvent
18 Apr 2026depthfirst's automated analysis flags the rewrite overflow
21 Apr 2026Reported to the nginx team via a GitHub security advisory
22 Apr 2026Upstream fix authored (published with the release on 13 May)
13 May 2026F5 advisory and depthfirst write-up; nginx 1.31.0 / 1.30.1 and NGINX Plus R36 P4 / R32 P6 released
16 May 2026VulnCheck reports exploitation attempts against its honeypots
22 May 2026Follow-up CVE-2026-9256 fixed in 1.31.1 / 1.30.2

Questions

Frequently asked questions

No. A stock configuration does not trigger the bug. It requires a rewrite directive whose replacement contains a question mark, followed in the same scope by a rewrite, if or set directive that reads an unnamed capture such as $1. Many sites never use that combination, so audit your configuration before assuming you are exposed.

The reliable outcome is a worker crash and restart, which is a denial of service. F5 states that code execution is possible where ASLR is disabled or bypassed. depthfirst's proof of concept runs with ASLR disabled, and a third-party proof of concept claims an ASLR bypass by chaining a separate file-read flaw. Treat it as potential RCE and patch urgently regardless of your ASLR status.

Open source nginx 1.31.0 (mainline) and 1.30.1 (stable) contain the fix, as do NGINX Plus R36 P4, R32 P6 and the PLS.37 release line. Distribution packages ship it under their own numbers, such as Debian bookworm 1.22.1-9+deb12u7 and Ubuntu noble 1.24.0-2ubuntu7.8. Restart nginx after upgrading so workers reload the patched binary.

Yes, by removing the trigger. Wherever a directive after a rewrite with a question mark reads an unnamed capture such as $1, use a named capture like $old_path instead. Named captures do not go through the vulnerable escaping path. This is a stopgap: upgrade as soon as you can, because related script-engine bugs were fixed in later releases.

Attempts have been seen. VulnCheck reported exploitation attempts against its honeypot network from 16 May 2026, three days after disclosure and the public proof of concept. As of 24 October 2026 the vulnerability is not listed in the CISA Known Exploited Vulnerabilities catalogue, but that is no reason to wait: internet-facing nginx with the vulnerable pattern should be patched now.

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.

  1. 01NVD — CVE-2026-42945 · NVD
  2. 02nginx security advisories · nginx.org
  3. 03F5 advisory K000161019 · F5
  4. 04NGINX Rift: achieving nginx RCE via an 18-year-old vulnerability · depthfirst
  5. 05nginx fix commit 524977e (rewrite escaping / buffer overrun) · nginx GitHub
  6. 06Debian security tracker — CVE-2026-42945 · Debian
  7. 07Ubuntu — CVE-2026-42945 · Ubuntu
  8. 08NGINX Plus release notes · F5 NGINX docs
  9. 09Attackers are exploiting critical NGINX vulnerability (CVE-2026-42945) · Help Net Security

Last updated