← Back to Feed CACHED · 2026-10-20 09:45:01 · CACHE_KEY CVE-2026-15176
CVE-2026-15176 · CWE-122 · Disclosed 2026-10-14

NGINX Open Source and Plus alias directive with rewrite heap buffer overflow via $request_filename

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

A loaded gun with a safety catch — NGINX's heap overflow only fires when three rare config directives line up and ASLR looks the other way

CVE-2026-15176 is a heap-based buffer overflow in ngx_http_core_module triggered when a location block combines the alias directive with a rewrite rule, and a set or return directive references $request_filename — or when $request_filename appears in an access log_format. An unauthenticated attacker sends crafted HTTP requests that cause the NGINX worker process to write past a heap buffer, crashing and restarting the worker. Code execution is theoretically possible but requires ASLR to be disabled or bypassed. The bug is ancient — every NGINX build from 0.1.29 through 1.31.6 (spanning 17+ years) carries it. Fixed versions are 1.31.7 (mainline), 1.30.6 (stable), and NGINX Plus 37.0.5.1 / 37.1.0.1. The advisory also covers NGINX Ingress Controller, Gateway Fabric, and Instance Manager.

F5 rates this HIGH 8.1 under CVSS v3.1 and bumps it to CRITICAL 9.2 under v4.0, both reflecting the theoretical RCE ceiling. That ceiling is misleading for most defenders. The C:H/I:H/A:H impact triplet assumes full code execution, but on any modern Linux kernel (which is nearly every production NGINX host), ASLR is on by default and heap-layout randomization makes weaponized RCE extremely difficult without an additional info-leak primitive — none of which has been demonstrated. The *reliable* outcome is a worker-process crash that NGINX's master process auto-restarts in milliseconds. Combine that with the non-default configuration requirement and you have a DoS bug with a theoretical RCE tail, not the "unauthenticated remote code execution" headline the v4.0 score suggests. The vendor severity oversells the risk for the vast majority of deployments.

"Config-gated heap overflow in NGINX; reliable impact is transient DoS, not the RCE the score implies."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify target NGINX with vulnerable config

The attacker locates an internet-facing NGINX instance (trivial — ~58.5 million visible on Shodan). They then need the target to run a configuration that uses alias inside a location block combined with rewrite and a set/return referencing $request_filename, or $request_filename in an access log_format. This is a non-default pattern; the attacker cannot influence it remotely.
Conditions required:
  • NGINX version 0.1.29–1.31.6 or NGINX Plus R33–R37.0.4
  • Target config uses alias + rewrite + $request_filename pattern
Where this breaks in practice:
  • The alias+rewrite+$request_filename combination is a niche configuration pattern — most NGINX deploys use root, not alias, and rarely reference $request_filename in set/return
  • No remote fingerprinting method exists to confirm the vulnerable directive combination from the outside
Detection/coverage: Nuclei template and Nessus plugin not yet available as of 2026-10-20. nginx -T | grep -P 'alias|\$request_filename' is the local check.
STEP 02

Send crafted HTTP request to trigger heap overflow

The attacker crafts an HTTP request whose URI, after rewrite processing, causes the alias path concatenation to overflow the heap buffer when $request_filename is resolved. The manipulation occurs entirely within the worker's request-processing pipeline. No special headers, authentication, or session state is needed — just a malformed URI routed to the vulnerable location block.
Conditions required:
  • Network reachability to the NGINX listener (port 80/443)
  • Request routes to the specific location block with the vulnerable directive combination
Where this breaks in practice:
  • The exact crafted URI depends on the specific rewrite rules and alias path in the target's config, which the attacker must guess or enumerate
  • WAF or CDN in front of NGINX may normalize or reject malformed URIs before they reach the worker
Detection/coverage: NGINX error logs will show worker crash/restart signals (SIGSEGV/SIGABRT). Monitor nginx_connections_active drop + master-process respawn in metrics.
STEP 03

Worker crash → transient DoS

The crafted request triggers a heap buffer overflow in the worker process, causing an immediate crash (SIGSEGV). The NGINX master process detects the exit and respawns a replacement worker within milliseconds. Inflight connections handled by that worker are dropped. Repeated exploitation creates a sustained but low-volume DoS — each crash costs one worker and its active connections.
Conditions required:
  • Steps 1–2 succeeded
Where this breaks in practice:
  • Master process auto-restarts workers, so sustained DoS requires continuous attack traffic
  • Rate-limiting at the network edge or upstream CDN throttles repeated crash attempts
  • Multiple worker processes mean only a fraction of connections drop per crash
Detection/coverage: Spike in NGINX worker_connections resets, upstream 502/504 errors in load balancer, and core dumps in /var/log/nginx/ or systemd journal.
STEP 04

(Theoretical) RCE via heap corruption with ASLR bypass

If ASLR is disabled (kernel.randomize_va_space=0) or the attacker possesses a separate info-leak primitive to defeat ASLR, they can shape the heap overflow to overwrite function pointers or control structures in the worker process, achieving code execution as the nginx/www-data user. No public technique for ASLR bypass in this context has been demonstrated. F5's own advisory qualifies RCE as conditional on ASLR status.
Conditions required:
  • Steps 1–3 succeeded
  • ASLR disabled or bypassed via separate vulnerability
  • Attacker has knowledge of target heap layout (binary version, allocator behavior)
Where this breaks in practice:
  • ASLR is enabled by default on every mainstream Linux distribution since 2005 — disabling it requires explicit sysctl override
  • No public info-leak primitive for NGINX has been paired with this overflow
  • Worker runs as unprivileged user (nginx/www-data), so even successful RCE lands in a low-privilege context
  • PIE (Position Independent Executable) is enabled in most distro NGINX packages, adding code-segment randomization on top of ASLR
Detection/coverage: EDR/auditd alerts on unexpected child processes from nginx worker PID, outbound connections from nginx user, or writes outside web root.
03 · Compensating Control

1
HIGH 6.5→LOW 2.0
SEVERITY REDUCED
Audit and remove the vulnerable directive pattern — Run nginx -T | grep -cP '(alias|\$request_filename)' across your fleet. Any location block combining alias with rewrite and $request_filename in a set, return, or log_format is the trigger. Refactor to use root instead of alias, or remove $request_filename references from set/return/log_format. This eliminates the attack surface entirely regardless of version. Per the noisgate mitigation SLA for HIGH, deploy within 30 days.
2
HIGH 6.5→IGNORE 0.0
SEVERITY REDUCED
Upgrade NGINX to patched version — Apply NGINX Open Source 1.31.7 (mainline) or 1.30.6 (stable), or NGINX Plus 37.0.5.1 / 37.1.0.1. For containerized deployments (Ingress Controller, Gateway Fabric), update the base image — verify with nginx -v inside the running container, not just the host. Confirm old workers have exited: ps aux | grep 'nginx: worker' should show only new-PID processes. Per the noisgate remediation SLA for HIGH, patch within 180 days.
3
HIGH 6.5→MEDIUM 5.3
SEVERITY REDUCED
Verify ASLR is enabled fleet-wide — Run cat /proc/sys/kernel/randomize_va_space — value must be 2 (full randomization). Any host returning 0 or 1 is at elevated RCE risk for this and every other memory-corruption CVE. Add this to your hardening baseline. This does not fix the DoS path but eliminates the RCE escalation. Deploy within 30 days.
4
HIGH 6.5→MEDIUM 4.5
SEVERITY REDUCED
Deploy upstream health-check and circuit-breaker logic — If NGINX sits behind a load balancer or CDN, configure active health checks with short intervals (2–5s) and circuit-breaker thresholds so that a crashing NGINX instance is drained automatically. This does not prevent the crash but limits blast radius to sub-second blips rather than client-visible outages. Applicable within existing infrastructure — no NGINX changes needed.
What doesn't work
  • Generic WAF rules (ModSecurity, NGINX App Protect): The overflow is triggered by internal variable resolution during alias path mapping after rewrite — there is no distinguishable malicious payload pattern in the raw HTTP request that a WAF signature can match. The crafted URI looks like a normal path traversal attempt at best, but the trigger depends on the *server-side rewrite outcome*, not the request bytes.
  • Rate-limiting alone: While rate-limiting slows sustained DoS, a single crafted request crashes a single worker. An attacker cycling through low-rate requests from distributed IPs can maintain the crash loop below most rate-limit thresholds.
  • Disabling HTTP/3 or QUIC: Some reports conflate this CVE with the ngx_http_v3_module bugs (CVE-2026-97205). CVE-2026-15176 affects ngx_http_core_module and is triggered over HTTP/1.1 and HTTP/2 — disabling HTTP/3 does not help.
04 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNone reported. F5 states no evidence of active exploitation. Not listed in CISA KEV as of 2026-10-20.
Proof-of-ConceptNo public PoC. Checked pocindex.io, GitHub (CVE-2026-15176), ExploitDB, and Nuclei templates — no results. Internally discovered by F5 (tracked as NPS-139), suggesting the trigger details are not public.
EPSS0.00516 (0.52%) — low exploitation probability. Roughly 55th–60th percentile, reflecting the config-dependency and absence of weaponized tooling.
KEV StatusNot listed in CISA Known Exploited Vulnerabilities catalog as of 2026-10-20.
CVSS VectorCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H = 8.1 HIGH. CVSS v4.0 scores 9.2 CRITICAL. The AC:H reflects server-side conditions, but the C:H/I:H impact assumes successful RCE — which requires ASLR bypass not captured in the vector.
Affected VersionsNGINX Open Source 0.1.29–1.31.6 (17+ years); NGINX Plus R33–R36, 37.0.0–37.0.4. Also affects NGINX Ingress Controller, Gateway Fabric, and Instance Manager per F5 advisory.
Fixed VersionsNGINX Open Source 1.31.7 (mainline) / 1.30.6 (stable); NGINX Plus 37.0.5.1 / 37.1.0.1. Distro backports pending — check apt changelog nginx / rpm -q --changelog nginx for your distro's patched package.
Internet ExposureShodan indexes ~58.5 million NGINX-identified hosts. However, the vulnerable *configuration pattern* (alias + rewrite + $request_filename) is a strict subset — no public data on prevalence, but alias is far less common than root in production configs.
Disclosure & CreditDisclosed 2026-10-14 via F5 out-of-band advisory K000162416. Discovered internally by F5 (NPS-139). Other CVEs in the same batch credited to Matt Suiche (Tolmo) and Mateusz Gierblinski.
Related CVEsPatched alongside CVE-2026-97205 (use-after-free, AIO+SSI) and CVE-2026-93479 (heap overflow, map directive captures) — all three rated 8.1/9.2. Review your exposure to all three simultaneously.

Sources.

  1. F5 Advisory K000162416
  2. NGINX Security Advisories
  3. CybersecurityNews — Multiple NGINX Flaws
  4. SecurityOnline — F5 Patches Three NGINX Vulnerabilities
  5. BleepingComputer — F5 Out-of-Band Patches
  6. LinuxSecurity — NGINX Vulnerability Config Check
  7. SecurityAffairs — F5 Addressed Critical RCE Flaws
  8. Strix.ai CVE-2026-15176 Intel
05 · The Call

Final Verdict
= UNCHANGED to HIGH (6.5/10)

Why this verdict

  • Configuration gate narrows the reachable population: The vulnerable directive combination (alias + rewrite + $request_filename in set/return/log_format) is non-default and uncommon. Most production NGINX configs use root, not alias, and rarely reference $request_filename in flow-control directives. This is a material reduction in exploitable surface that AC:H only partially captures.
  • ASLR collapses the RCE path on modern systems: Every mainstream Linux distro has shipped with kernel.randomize_va_space=2 since 2005. Distro NGINX packages are compiled as PIE binaries. No public info-leak primitive exists for NGINX to chain with this overflow. The vendor's own advisory conditions RCE on "ASLR disabled or bypassed" — on modern production hosts, the realistic ceiling is worker crash, not code execution.
  • Reliable impact is transient DoS, not persistent compromise: Worker crashes are auto-restarted by the master process in milliseconds. Sustained DoS requires continuous attack traffic, which is detectable and rate-limitable. There is no data exfiltration, no persistence, and no lateral movement from a crash.
  • Role multiplier: NGINX is a canonical network-edge component — Shodan shows ~58.5M instances, and a large fraction serve as the primary internet-facing reverse proxy, API gateway, or Kubernetes Ingress Controller. On a perimeter NGINX handling production traffic, even transient DoS is operationally painful (dropped connections, 502 storms to clients). If the RCE path *did* succeed on such a host, the blast radius would be severe: the attacker lands on the DMZ pivot point with visibility into internal backends. This keeps the floor at HIGH despite the friction. However, the reliable outcome (transient worker crash, not RCE) and the configuration gate prevent elevation to CRITICAL — the blast radius of a *crash* is availability-only and auto-recovering, not fleet-compromise.
  • No exploitation ecosystem: Zero public PoCs, no scanning activity on GreyNoise, EPSS at 0.52%, not KEV-listed. The bug was found internally by F5. There is no attacker tooling to lower the barrier.

Why not higher?

Upgrading to CRITICAL would require either a reliable RCE path or a DoS that is persistent and unrecoverable. Neither exists here. RCE is gated by ASLR bypass with no demonstrated technique, and the DoS auto-recovers via master-process worker respawn. The configuration prerequisite further limits the population — this is not a universal NGINX flaw despite the 17-year version range. The CVSS v4.0 score of 9.2 overweights a theoretical RCE ceiling that has no practical path on hardened hosts.

Why not lower?

NGINX's canonical role as the internet's most deployed reverse proxy and ingress controller means even a config-gated DoS affects high-value infrastructure. A sustained crash loop against a production NGINX fronting thousands of backends causes real revenue and availability impact. The 17-year version range means *every* unpatched NGINX instance is one config change away from exposure. And while ASLR bypass is hard, it is not impossible — embedded/IoT NGINX deployments, older kernels, or container runtimes with reduced entropy could present edge cases. The floor stays at HIGH.

06 · Verification

Crowdsourced verification payload.

Run this script on each NGINX host as root (or any user with read access to NGINX configs and the nginx binary). Invoke: sudo bash check_cve_2026_15176.sh. It checks the running NGINX version against fixed releases and scans the active configuration for the vulnerable directive pattern.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# CVE-2026-15176 checker — NGINX alias+rewrite+$request_filename heap overflow
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
set -uo pipefail

NGINX_BIN="${NGINX_BIN:-nginx}"
RESULT="UNKNOWN"

# --- Locate nginx binary ---
if ! command -v "$NGINX_BIN" &>/dev/null; then
  echo "UNKNOWN — nginx binary not found in PATH"
  exit 2
fi

# --- Extract version ---
VER_LINE=$($NGINX_BIN -v 2>&1) || true
VER=$(echo "$VER_LINE" | grep -oP '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
if [[ -z "$VER" ]]; then
  echo "UNKNOWN — cannot parse nginx version from: $VER_LINE"
  exit 2
fi
IFS='.' read -r MAJOR MINOR PATCH <<< "$VER"
echo "[*] Detected nginx version: $VER"

# --- Version check ---
PATCHED=0
# Mainline branch: fixed in 1.31.7
if (( MAJOR > 1 )); then PATCHED=1; fi
if (( MAJOR == 1 && MINOR > 31 )); then PATCHED=1; fi
if (( MAJOR == 1 && MINOR == 31 && PATCH >= 7 )); then PATCHED=1; fi
# Stable branch: fixed in 1.30.6
if (( MAJOR == 1 && MINOR == 30 && PATCH >= 6 )); then PATCHED=1; fi

if (( PATCHED == 1 )); then
  echo "[+] Version $VER is at or above the fix."
  echo "PATCHED"
  exit 0
fi
echo "[-] Version $VER is BELOW the fix (needs 1.31.7+ or 1.30.6)."

# --- Configuration audit ---
echo "[*] Dumping active configuration..."
CONF_DUMP=$($NGINX_BIN -T 2>/dev/null) || CONF_DUMP=""
if [[ -z "$CONF_DUMP" ]]; then
  echo "[!] Cannot dump config (need root?). Checking default paths..."
  for f in /etc/nginx/nginx.conf /usr/local/nginx/conf/nginx.conf; do
    [[ -r "$f" ]] && CONF_DUMP=$(cat "$f" 2>/dev/null) && break
  done
fi

HAS_ALIAS=0; HAS_REWRITE=0; HAS_REQ_FN=0
if [[ -n "$CONF_DUMP" ]]; then
  echo "$CONF_DUMP" | grep -qP '^\s*alias\s' && HAS_ALIAS=1
  echo "$CONF_DUMP" | grep -qP '^\s*rewrite\s' && HAS_REWRITE=1
  echo "$CONF_DUMP" | grep -qP '\$request_filename' && HAS_REQ_FN=1
fi

echo "[*] Config signals: alias=$HAS_ALIAS rewrite=$HAS_REWRITE \$request_filename=$HAS_REQ_FN"

if (( HAS_ALIAS && HAS_REWRITE && HAS_REQ_FN )); then
  echo "[!] VULNERABLE configuration pattern DETECTED."
  echo "    alias + rewrite + \$request_filename all present."
  echo "VULNERABLE"
  exit 1
elif (( HAS_ALIAS && (HAS_REWRITE || HAS_REQ_FN) )); then
  echo "[-] Partial pattern detected (alias present with rewrite or \$request_filename)."
  echo "    Manual review recommended — full triple may exist in included files."
  echo "VULNERABLE"
  exit 1
else
  echo "[*] Vulnerable directive pattern NOT detected in active config."
  echo "    Version is still unpatched — a future config change could expose this."
  echo "VULNERABLE"
  exit 1
fi