A race between nginx's read loop and its own TLS handshake — but only if an attacker already sits between nginx and its backend
CVE-2026-1642 is a race condition in how nginx processes upstream TLS connections. When nginx is configured as a reverse proxy to a TLS-backed upstream (HTTP/1.x, HTTP/2, gRPC, uWSGI), the event loop can process a READ event on the socket before the TLS handshake with the upstream completes. An attacker with a MITM position between nginx and its upstream server can flood the socket with plaintext HTTP during that narrow window; nginx will accept those bytes as if they came from the authenticated TLS peer. Affected: nginx 1.3.0 through 1.29.4 (both OSS and Plus). Fixed in 1.28.2 (stable) and 1.29.5 (mainline). The impact vector is VC:N/VI:H/VA:N — integrity only, no confidentiality or availability loss.
F5 rated this HIGH (CVSS v4.0 8.2) but the same vector maps to CVSS v3.1 5.9 (Medium) — a telling gap. The v4.0 score inflates because it doesn't fully weight the *upstream-side* MITM prerequisite. In practice, upstream traffic runs across a data-center fabric, VPC peering, service mesh, or private link — networks where an attacker with MITM capability already has far more damaging options (steal secrets, replace the backend outright, harvest tokens). Vendor severity is overstated for the typical enterprise deployment; MEDIUM is a truer read.
3 steps from start to impact.
Obtain MITM on the nginx→upstream path
- Layer-2 or layer-3 path insertion between proxy and upstream
- Ability to observe the TCP handshake to the upstream in real time
- Backend traffic is almost never on a shared L2 segment an outside attacker can reach
- Service meshes (Istio, Linkerd) and private-link fabrics remove the MITM surface
- Anyone with this position already owns your east-west network — dozens of higher-impact attacks are available first
Win the race against the TLS Client Hello
- Precise timing tooling — e.g., a custom scapy/nftables shim on the MITM node
- Knowledge of the exact request pattern nginx will forward
- Race window is on the order of milliseconds
- TLS resumption / keep-alive short-circuits the vulnerable path on subsequent requests
- Any TLS-terminating middlebox in front of the upstream (stunnel, envoy) closes the window
Inject a malicious response body / headers
proxy_cache), bypass a WAF that only inspects the client-facing leg, or smuggle cookies/CSP headers back to the browser. No confidentiality is lost — the attacker is *writing*, not reading — but downstream user sessions can be tampered with.proxy_cacheenabled for cache poisoning to persist beyond a single request- Response reaches a browser or downstream service that trusts the header set
proxy_cache_keyand cache-control headers on the upstream may prevent caching- Downstream client validates content signatures (JWT, HTTPS pinning at browser)
- Integrity-only impact — no code execution primitive from this bug alone
The supporting signals.
| CVE | CVE-2026-1642 — nginx SSL Upstream Injection (race condition on upstream TLS) |
|---|---|
| In the wild | No known exploitation. Not on CISA KEV as of 2026-07-23. No public campaigns tracked. |
| Public PoC | No weaponized PoC published. Root-cause writeup in CVEReports analysis describes the READ-before-handshake race; reproduction requires a custom MITM harness. |
| EPSS | 0.00012 (~0.05 percentile) — statistically zero probability of exploitation in the next 30 days |
| CVSS | v4.0 8.2 HIGH (F5) vs v3.1 5.9 MEDIUM — vector AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N. Integrity-only; MITM prerequisite is the hidden cost. |
| Affected | nginx OSS and NGINX Plus, 1.3.0 → 1.29.4. Applies only when proxying to a TLS upstream (proxy_pass https://…, gRPC over TLS, uWSGI+SSL). |
| Fixed | 1.28.2 (stable) released 2026-02-04, 1.29.5 (mainline). Debian/Ubuntu/RHEL backports followed within 2 weeks. |
| Discovered by | F5 internal research; disclosure coordinated by Jan Schaumann (netmeister.org) via oss-security 2026-02-04 |
| Exposure | Shodan shows ~35M nginx instances on the internet, but the vulnerable path is *upstream-facing* — not directly probeable from the internet. Real exposed surface is far smaller. |
| CWE | CWE-349 — Acceptance of Extraneous Untrusted Data With Trusted Data |
noisgate verdict.
Downgraded from HIGH to MEDIUM because the single decisive factor is the upstream-side MITM prerequisite: an attacker must already control the network segment between your nginx proxy and its backend, which sits inside the datacenter/VPC trust boundary. Any adversary with that position has strictly more impactful primitives available than injecting a response body, and the impact vector is integrity-only (VC:N/VI:H/VA:N).
Why this verdict
- MITM position is the gate: the attacker must already sit between nginx and its upstream — a network position that, in modern datacenter and cloud fabrics, implies prior compromise of the east-west network. That single prerequisite cuts realistic exposure by orders of magnitude.
- Integrity-only impact: the bug is
VI:HwithVC:NandVA:N. No code execution, no credential theft, no data exfiltration primitive. The worst case is cache poisoning or WAF bypass — recoverable and detectable. - Race window is narrow: exploitation requires winning a millisecond-scale race against the TLS Client Hello. TLS session resumption and any TLS-terminating middlebox in the upstream path shut the window entirely.
- Role multiplier — reverse proxy fronting backend services: nginx here is a canonical high-value role (traffic edge), but the chain fails when the upstream leg is a service mesh, private link, or same-host loopback. Even in a plausible worst-case (poison the cache of a customer-facing tenant), blast radius is bounded to that tenant's cached responses, not fleet-wide.
- No KEV, EPSS ~0.0001: F5 disclosed it responsibly, patch shipped same day, and six months later there is still no known weaponization.
Why not higher?
HIGH would require either a realistic remote-unauthenticated path (there is none — MITM on upstream is not that) or fleet-scale impact. Neither holds. The v4.0 8.2 score treats AT:P (attack requirements present) as a smaller discount than it deserves for this specific prerequisite class; v3.1's 5.9 MEDIUM is closer to operational reality.
Why not lower?
LOW would ignore that nginx is the most-deployed reverse proxy on earth and that shared-tenancy cloud, misconfigured service meshes, and flat east-west VLANs do exist. Where the MITM position is achievable, integrity compromise of the upstream response is a real cache-poisoning / WAF-bypass primitive. MEDIUM keeps it on the patch cycle without displacing genuinely urgent work.
What to do — in priority order.
- Upgrade nginx to 1.28.2 or 1.29.5+ — This is the actual fix — schedule within the noisgate remediation SLA for MEDIUM (≤365 days), but prefer next standard maintenance window. Distro backports are shipped for Debian, Ubuntu, RHEL, Amazon Linux, Alpine.
- Verify upstream traffic runs over private link, VPC peering, or a service mesh with mTLS — Eliminates the MITM prerequisite entirely. If your
proxy_pass https://…targets are on the same VPC or reached via PrivateLink / Cloud Interconnect / a mesh sidecar, the exploitable surface collapses to zero. - Enable
proxy_ssl_verify onwith pinned upstream CA — Doesn't fix the race directly, but ensures the injected plaintext never gets promoted past the TLS layer on subsequent requests; also catches broader upstream tampering. - Disable
proxy_cacheon sensitive endpoints — Removes persistence for any injected response, cutting cache-poisoning impact even if the race is won for a single request.
- WAF rules on the client-facing leg — the injection happens on the upstream leg, so a client-side WAF sees the poisoned response after nginx has already accepted it.
- HSTS / client-side TLS pinning — these protect the browser↔nginx leg, not nginx↔upstream.
- Rate limiting — the race is a single-shot injection, not a volumetric attack.
- IP allowlisting the upstream — an attacker with MITM already sees traffic from the allowed IP; the allowlist doesn't stop injection.
Crowdsourced verification payload.
Run on each host that runs nginx (as root or a user in the nginx group). Example: sudo bash check-nginx-1642.sh. Detects both OSS and NGINX Plus builds; parses nginx -v and compares to the fixed versions.
#!/usr/bin/env bash
# check-nginx-1642.sh — detect CVE-2026-1642 exposure
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u
NGINX_BIN="$(command -v nginx || true)"
if [ -z "$NGINX_BIN" ]; then
echo "UNKNOWN: nginx not found in PATH"
exit 2
fi
VER_RAW="$($NGINX_BIN -v 2>&1)"
# e.g. "nginx version: nginx/1.24.0" or "nginx/1.29.5 (nginx-plus-r33)"
VER="$(echo "$VER_RAW" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)"
if [ -z "$VER" ]; then
echo "UNKNOWN: could not parse version from: $VER_RAW"
exit 2
fi
IFS=. read -r MAJ MIN PATCH <<<"$VER"
vuln=0
# Fixed: 1.28.2+ (stable) or 1.29.5+ (mainline). Anything else in 1.3.0..1.29.4 is vulnerable.
if [ "$MAJ" -eq 1 ]; then
if [ "$MIN" -lt 3 ]; then
vuln=0 # <1.3.0 not affected per advisory
elif [ "$MIN" -lt 28 ]; then
vuln=1
elif [ "$MIN" -eq 28 ] && [ "$PATCH" -lt 2 ]; then
vuln=1
elif [ "$MIN" -eq 29 ] && [ "$PATCH" -lt 5 ]; then
vuln=1
fi
fi
# Check if proxy_pass https:// or grpcs:// is actually configured — the vuln path
CONF_DIR="/etc/nginx"
HAS_TLS_UPSTREAM=0
if [ -d "$CONF_DIR" ]; then
if grep -REq 'proxy_pass[[:space:]]+https://|grpc_pass[[:space:]]+grpcs://|uwsgi_pass.*ssl' "$CONF_DIR" 2>/dev/null; then
HAS_TLS_UPSTREAM=1
fi
fi
if [ "$vuln" -eq 1 ]; then
if [ "$HAS_TLS_UPSTREAM" -eq 1 ]; then
echo "VULNERABLE: nginx $VER with TLS upstream configured (CVE-2026-1642)"
else
echo "VULNERABLE: nginx $VER (no TLS upstream currently configured — still upgrade)"
fi
exit 1
fi
echo "PATCHED: nginx $VER (>= 1.28.2 or >= 1.29.5)"
exit 0
If you remember one thing.
proxy_pass https://… is actually configured *and* whether the upstream leg traverses shared infrastructure (multi-tenant cloud, cross-VPC, WAN) — those are the only realistic exposure surfaces. Deprioritize hosts where upstreams are same-VPC, mesh-terminated, or loopback. Do not page anyone; do not open a war room.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.