← Back to list

Nginx CVE-2026-42945: 18-Year-Old Bug, PoC & Fix Explained

itadol5j

Nginx CVE-2026-42945

🚨 Nginx's 18-Year-Old Vulnerability CVE-2026-42945: How It Works, the PoC, and the Fix

On May 13, 2026, security research firm depthfirst, together with F5, dropped a bombshell disclosure of one of the most severe vulnerabilities in NGINX history — CVE-2026-42945:

  • CVSS v4.0 score of 9.2: a high-severity flaw
  • Heap buffer overflow: can lead to remote code execution (RCE)
  • Lurking for 18 years: in the codebase since 2008
  • 9.75 million sites affected worldwide: over 2.54 million websites in China affected
  • PoC is public: successfully reproduced by QiAnXin

This is an NGINX core module vulnerability of historic proportions — an attacker can take over a server remotely with a single crafted HTTP request.

🔍 Vulnerability Overview

Basic Info

Property Details
CVE ID CVE-2026-42945
CVSS score v4.0: 9.2 | v3.1: 8.1
Vulnerability type Heap-based Buffer Overflow
Threat type Remote code execution (RCE), denial of service (DoS)
Exploitation requirements No authentication needed, just a crafted HTTP request
Affected component ngx_http_rewrite_module (a built-in NGINX core module)
Discovered by depthfirst (found by its automated system in 6 hours)

Impact scope

  • 9.75 million sites worldwide affected
  • 2.54 million websites in China affected
  • NGINX powers roughly 1/3 of all websites, so the blast radius is enormous
  • The code has been there since 2008, lying dormant for 18 years

⚠️ Trigger Conditions

All three conditions must be met

Exploitation requires a specific combination of configuration conditions:

Condition Description Example
1. Unnamed PCRE captures The rewrite directive uses unnamed capture groups $1, $2, $3…
2. Replacement string contains a question mark The replacement string contains a ? character /profile.php?id=$1&tab=$2
3. Followed by rewrite/if/set Another directive comes right after the rewrite directive rewrite … last; if (…) { … }

A vulnerable example

# 易受攻击配置
rewrite ^/users/([0-9]+)/profile/(.*)$ /profile.php?id=$1&tab=$2 last;
# 后跟其他指令
if ($arg_debug) {
    set $debug_flag 1;
}

This config hits all three conditions at once: unnamed captures $1/$2, a ? in the replacement string, followed by an if directive.

🔬 How the Bug Works

State inconsistency between two processing phases

The NGINX script engine uses two-phase processing:

  • Phase one: calculate the required buffer size
  • Phase two: copy data into the buffer

The core of the bug is mishandling of the is_args flag:

Phase is_args state Processing logic Result
Length calculation phase is_args = 0 Returns the raw capture length Buffer size is underestimated
Data copy phase is_args = 1 Calls ngx_escape_uri, expanding each byte to 3 bytes Heap buffer overflow

Step by step

  1. A rewrite directivewith unnamed captures $1/$2
  2. The replacement stringcontains ?, which sets is_args = 1
  3. Length calculation phase: uses a freshly initialized sub-engine, is_args = 0
  4. Returns the raw length: allocates a heap buffer that's too small
  5. Data copy phase: uses the main engine, is_args = 1
  6. Calls ngx_escape_uri: expands bytes, overflowing the buffer
  7. Attacker-controlled URI datagets written past the end of the buffer

Exploitation technique

Cross-request heap Feng Shui:

  • POST request bodiesspray the heap (since URIs can't contain null bytes)
  • Overflow datacorrupts the cleanup pointer of an adjacent ngx_pool_t
  • Forge ngx_pool_cleanup_s, pointing it at system()
  • When the pool is destroyedthe system() call fires
  • achieving RCE

ASLR impact

  • ASLR enabled: only crashes worker processes (DoS)
  • ASLR disabled: full remote code execution (RCE) is possible

📊 Affected Versions

NGINX Open Source

Version range Fixed version
0.6.27 – 1.30.0 1.31.0, 1.30.1

NGINX Plus

Version range Fixed version
R32 – R36 R36 P4, R35 P2, R32 P6

Other affected components

  • NGINX Instance Manager: 2.16.0 – 2.21.1
  • NGINX App Protect WAF: 4.9.0 – 5.8.0
  • NGINX Ingress Controller: 3.5.0 – 5.4.1
  • NGINX Gateway Fabric: 1.3.0 – 2.5.1
  • F5 DoS for NGINX: 4.8.0

🔥 PoC Status

PoC is public

  • GitHub repo: https://github.com/DepthFirstDisclosures/Nginx-Rift
  • Reproduced by QiAnXin: security researchers at its Threat Intelligence Center successfully reproduced it
  • Technical details are public: depthfirst published a technical analysis
  • In-the-wild exploitation: none observed so far

How to use the PoC

# 构建容器
./setup.sh

# 启动易受攻击的 NGINX 服务器
docker compose -f env/docker-compose.yml up

# 执行 PoC 获取 Shell
python3 poc.py --shell

✅ Fixes

Option 1: Upgrade

# 升级到修复版本
NGINX Open Source >= 1.31.0
NGINX Open Source >= 1.30.1
NGINX Plus >= R32 P6
NGINX Plus >= R36 P4

# 升级后重启 NGINX
nginx -s reload

Option 2: Change your config (mitigation)

Replace unnamed capture groupswith named capture groups:

# 易受攻击配置(未命名捕获)
rewrite ^/users/([0-9]+)/profile/(.*)$ /profile.php?id=$1&tab=$2 last;

# 修复后配置(命名捕获)
rewrite ^/users/(?[0-9]+)/profile/(?.*)$ /profile.php?id=$user_id&tab=$section last;

Named capture groups don't trigger the bug.

Option 3: Audit your config

Check whether you have a vulnerable configuration:

# 搜索易受攻击的 rewrite 指令
grep -E "rewrite.*\$[0-9]+.*\?.*(rewrite|if|set)" /etc/nginx/nginx.conf
grep -rE "rewrite.*\$[0-9]+.*\?.*(rewrite|if|set)" /etc/nginx/conf.d/

🔍 How It Was Found

Found by an automated system

depthfirst's security analysis system:

  • Within 6 hours it found 5 issues
  • 4 were confirmed by NGINX
  • CVE-2026-42945 is the most severe of the bunch
  • Traceable back to 2008, present in nearly every standard build

Other related vulnerabilities

  • CVE-2026-42946: memory corruption issue
  • CVE-2026-40701: memory corruption issue
  • CVE-2026-42934: memory corruption issue

📝 Summary

CVE-2026-42945 is one of the most severe vulnerabilities in NGINX history:

  • Lurked for 18 years: in the codebase since 2008
  • CVSS 9.2: heap buffer overflow that can lead to RCE
  • Trigger: rewrite with unnamed captures + a ? in the replacement string + a directive right after
  • Impact: 9.75 million sites worldwide, 2.54 million in China
  • PoC is public: GitHub repo + reproduced by QiAnXin
  • Fix: upgrade, or switch to named capture groups

After 18 years in hiding, this bug is out — upgrade or patch your config ASAP.

Official advisory: https://my.f5.com/manage/s/article/K000161019

PoC repo: https://github.com/DepthFirstDisclosures/Nginx-Rift

Technical analysis: https://depthfirst.com/research/nginx-rift