Like leaving a loaded mousetrap in a locked room that only certain guests have the key to
CVE-2026-42530 is a use-after-free in NGINX Open Source's ngx_http_v3_module, affecting only mainline versions 1.31.0 and 1.31.1 (fixed in 1.31.2, released 2026-06-17). The bug lives in HTTP/3's QPACK header-compression logic: a session-scoped pointer retains a reference to memory allocated from a unidirectional encoder stream's pool. When that stream closes, the pool is freed, but the session keeps a dangling pointer. A second encoder stream on the same connection then writes into freed heap, crashing the worker. CyStack researcher Trung Nguyen characterized the root cause as a "lifetime mismatch" between the connection-level session and the transient stream. The flaw also impacts NGINX Gateway Fabric 2.0.0–2.6.3, NGINX Ingress Controller 3.5.0–3.7.2 / 4.0.0–4.0.1 / 5.0.0–5.5.0, and NGINX Instance Manager 2.17.0–2.22.0.
F5's vendor rating of HIGH / 8.1 (CVSS v3.1) is honest — the AC:H reflects that code execution requires ASLR to be disabled or bypassed, which is uncommon on modern Linux. The CVSS v4.0 bump to 9.2 over-indexes on the theoretical RCE ceiling and under-weights the narrow deployment preconditions: the server must be on mainline 1.31.x, compiled with --with-http_v3_module, configured with listen … quic and http3 on, and reachable over UDP 443. Reliable DoS (worker restart via crash) requires none of the ASLR gymnastics and is the more realistic impact. The vendor score is directionally right; we shave it to 7.5 to reflect the compounding opt-in gates that limit real-world exposure.
5 steps from start to impact.
Identify NGINX with HTTP/3 enabled
alt-svc: h3 headers or discovers open UDP 443 via Shodan/Censys/FOFA. Only NGINX mainline 1.31.0–1.31.1 compiled with --with-http_v3_module and configured with listen 443 quic is reachable. The v4ltonn scanner PoC automates this step using aioquic.- Target runs NGINX 1.31.0 or 1.31.1
- HTTP/3 QUIC is compiled in and enabled in config
- UDP 443 is open to the attacker
- 1.31.x is mainline (development), not the stable branch — most production fleets run stable
- HTTP/3 requires both compile-time flag and explicit config directives
- Many firewalls and cloud security groups block UDP 443 by default
http.component:nginx http.headers.alt-svc:h3; Tenable plugin 321538 (remote version check); v4ltonn/CVE-2026-42530 scanner PoCEstablish QUIC connection and open QPACK encoder stream
insert_buffer for header compression from this stream's connection pool. This step is standard protocol behavior and carries no anomaly signal.- TLS 1.3 handshake succeeds (QUIC requirement)
- NGINX worker accepts the connection
- QUIC libraries required (e.g.,
aioquic,quiche,ngtcp2) — not as trivial as raw TCP exploitation
Close and reopen the encoder stream
insert_buffer memory. The session-level pointer to this buffer is now dangling. The attacker then opens a second QPACK encoder stream on the same connection. NGINX processes this without checking that the prior stream was already consumed, writing into freed memory. Patched versions (1.31.2+) reject the second encoder stream with QUIC error code 0x103; vulnerable versions accept it and return 0x201.- Vulnerable code path exists (1.31.0–1.31.1)
- Connection is still alive
- Timing must be right — the freed pool must not be reallocated before the second stream arrives, though in practice NGINX's slab allocator makes this reliable
Trigger worker crash (DoS)
- Steps 1–3 succeeded
- Workers auto-restart; attacker must sustain the attack to maintain DoS
- Rate limiting on QUIC connection setup can throttle the attack
signal 11 (SIGSEGV) in error.logAchieve RCE (conditional)
kernel.randomize_va_space=0), or the attacker can infoleak the heap layout via a side channel, the freed memory can be groomed to place attacker-controlled data at the dangling pointer. On the next dereference, NGINX jumps to attacker-supplied code. This is a theoretical escalation path; no public exploit achieves it.- ASLR disabled or bypassed
- Attacker can groom the NGINX worker heap
- ASLR is enabled by default on every mainstream Linux distro since ~2005
- No public heap-grooming technique for this specific NGINX code path exists
- NGINX workers run as unprivileged
nginxorwww-datauser, limiting post-exploitation value without a second privilege-escalation bug
listen … quic and http3 on directives — Eliminates the attack surface entirely — the vulnerable code path in ngx_http_v3_module is never reached. This is the fastest mitigation and should be deployed within the noisgate mitigation SLA of 30 days (HIGH). If HTTP/3 is not business-critical, this can serve as permanent remediation.limit_conn and limit_req or upstream firewall rate limiting on UDP 443 reduces the attacker's ability to sustain repeated worker crashes. Does not eliminate the vulnerability but raises the bar for impactful DoS. Deploy as a bridge control while scheduling patching.execve and similar syscalls from the worker, and a read-only filesystem prevents payload drops. Already standard in hardened Kubernetes pods.- WAF in front of NGINX — virtually no commercial WAF decodes QUIC/HTTP/3 at the protocol level today. The malicious QPACK encoder stream manipulation happens inside the encrypted QUIC tunnel and is invisible to a TCP-layer WAF.
- Enabling ASLR — ASLR is already enabled by default everywhere. It mitigates the theoretical RCE escalation but does nothing against the reliable DoS path, which is the primary impact.
- NGINX
proxy_protocolorreal_iprestrictions — these operate at HTTP layer after the QUIC handshake; the vulnerability triggers during QUIC stream setup, before any HTTP request is processed.
The supporting signals.
| In-the-Wild Exploitation | No confirmed exploitation. F5 made no mention of active attacks at disclosure (2026-06-17). Not listed in CISA KEV as of 2026-10-07. No GreyNoise tags observed. |
|---|---|
| Proof-of-Concept Availability | Scanner/detector PoCs exist. v4ltonn/CVE-2026-42530 (Python/aioquic — sends dual QPACK encoder streams, checks error codes), 0xBlackash/CVE-2026-42530 (Python — safe version checker). Both are detection-only; no weaponized RCE exploit is public. |
| EPSS | 0.01145 (~98.5th percentile). Elevated relative to baseline, reflecting the unauthenticated-remote vector, but consistent with no observed exploitation. |
| CISA KEV Status | Not listed as of 2026-10-07. |
| CVSS Vectors | v3.1: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H (8.1 HIGH) — AC:H reflects ASLR requirement for RCE. v4.0: 9.2 CRITICAL — inflated by worst-case RCE ceiling without weighting real-world ASLR prevalence. |
| Affected Versions | NGINX Open Source 1.31.0–1.31.1 (mainline only). Also: Gateway Fabric 2.0.0–2.6.3, Ingress Controller 3.5.0–3.7.2 / 4.0.0–4.0.1 / 5.0.0–5.5.0, Instance Manager 2.17.0–2.22.0. |
| Fixed Versions | NGINX Open Source 1.31.2 (2026-06-17). Gateway Fabric 2.6.4. Ingress Controller and Instance Manager patches per F5 advisory K000161616. |
| Scanning / Exposure | HTTP/3 advertised via alt-svc: h3 on ~39% of top sites (April 2026 data), but actual QUIC usage is ~21%. The subset running NGINX mainline 1.31.0–1.31.1 with HTTP/3 is a tiny fraction — mainline is a development track, not the stable branch most enterprises deploy. |
| Disclosure Date | 2026-06-17 (coordinated with F5 patch release). |
| Researcher | Trung Nguyen of CyStack. Described root cause as a "lifetime mismatch" between session-scoped pointer and stream-scoped pool allocation. |
Sources.
Why this verdict
- Narrow version window: Only mainline 1.31.0 and 1.31.1 are affected — the stable branch that most enterprises deploy is untouched. This dramatically limits the reachable population versus a typical NGINX CVE.
- Opt-in attack surface: HTTP/3 requires compile-time flag (
--with-http_v3_module), explicit config (listen … quic; http3 on;), and open UDP 443. Each gate compounds downward from the vendor baseline. - ASLR kills the RCE path: ASLR is universally enabled on modern Linux. The reliable impact is DoS via worker crash, not code execution. Workers auto-restart, so sustained exploitation is needed for meaningful outage.
- Role multiplier: NGINX canonically occupies the network edge high-value role (reverse proxy, load balancer, API gateway, Kubernetes ingress). On an internet-facing NGINX ingress controller running 1.31.x with HTTP/3, a sustained DoS takes down all upstream services — blast radius is tenant/cluster-scale. The NGINX Ingress Controller's wide affected range (3.5.0–5.5.0) means the Kubernetes deployment scenario is real, not hypothetical. This floors the verdict at HIGH despite the opt-in gates.
- No exploitation uplift: No KEV listing, no observed in-the-wild exploitation, no weaponized RCE PoC. Only safe-check scanner PoCs exist. This supports staying at the floor rather than above it.
Why not higher?
The CVSS v4.0 score of 9.2 / CRITICAL over-counts RCE impact that depends on ASLR being disabled — a configuration essentially extinct in production Linux. The reliable impact is DoS with auto-recovery, not persistent compromise. The narrow mainline-only version range means the installed base is a fraction of total NGINX deployments; a CRITICAL rating would over-allocate patching urgency relative to CVEs hitting the stable branch.
Why not lower?
NGINX is a canonical edge component and the Ingress Controller's wide affected version range means Kubernetes clusters are in scope. Unauthenticated remote DoS of an edge proxy or ingress controller is operationally significant — even with auto-restart, sustained attacks degrade availability for every service behind it. The existence of working scanner PoCs lowers the skill bar for discovery. Dropping below HIGH would under-weight the deployment-role blast radius.
Crowdsourced verification payload.
Run this script on each NGINX host as any user with read access to the NGINX binary and config. Invoke with: bash check_cve_2026_42530.sh. No root required unless the NGINX binary path is restricted.
#!/usr/bin/env bash
# check_cve_2026_42530.sh — Detect CVE-2026-42530 exposure
# Checks: (1) NGINX version in affected range, (2) HTTP/3 module compiled in, (3) HTTP/3 enabled in config
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -euo pipefail
NGINX_BIN="${1:-$(command -v nginx 2>/dev/null || echo '')}"
if [[ -z "$NGINX_BIN" ]]; then
echo "UNKNOWN — nginx binary not found in PATH. Pass path as argument."
exit 2
fi
# Get version
VER_LINE=$($NGINX_BIN -v 2>&1 || true)
VER=$(echo "$VER_LINE" | grep -oP 'nginx/\K[0-9]+\.[0-9]+\.[0-9]+' || echo '')
if [[ -z "$VER" ]]; then
echo "UNKNOWN — could not parse NGINX version from: $VER_LINE"
exit 2
fi
echo "[*] NGINX version: $VER"
# Check if version is in affected range (1.31.0 or 1.31.1)
case "$VER" in
1.31.0|1.31.1)
AFFECTED=1
;;
*)
echo "PATCHED — version $VER is outside affected range (1.31.0–1.31.1)."
exit 0
;;
esac
# Check if http_v3_module is compiled in
BUILD_FLAGS=$($NGINX_BIN -V 2>&1 || true)
if echo "$BUILD_FLAGS" | grep -q 'http_v3_module'; then
echo "[!] HTTP/3 module (ngx_http_v3_module) is compiled into this binary."
H3_COMPILED=1
else
echo "PATCHED — version $VER is affected but ngx_http_v3_module is NOT compiled in. Not exploitable."
exit 0
fi
# Check if HTTP/3 is enabled in running config
CONFIG_DUMP=$($NGINX_BIN -T 2>/dev/null || echo 'CONFIG_UNREADABLE')
if [[ "$CONFIG_DUMP" == "CONFIG_UNREADABLE" ]]; then
echo "VULNERABLE — version $VER with http_v3_module compiled in. Could not read config to check if HTTP/3 is active (run as root or nginx user). Assume vulnerable."
exit 1
fi
if echo "$CONFIG_DUMP" | grep -qE 'listen.*quic|http3\s+on'; then
echo "VULNERABLE — NGINX $VER with HTTP/3 (QUIC) enabled in configuration. CVE-2026-42530 is exploitable."
exit 1
else
echo "PATCHED — version $VER with http_v3_module compiled in but HTTP/3 is NOT enabled in config. Not currently exploitable."
exit 0
fi