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

🚨 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
- A rewrite directivewith unnamed captures $1/$2
- The replacement stringcontains ?, which sets is_args = 1
- Length calculation phase: uses a freshly initialized sub-engine, is_args = 0
- Returns the raw length: allocates a heap buffer that's too small
- Data copy phase: uses the main engine, is_args = 1
- Calls ngx_escape_uri: expands bytes, overflowing the buffer
- 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