← Back to Feed CACHED · 2026-09-30 01:39:49 · CACHE_KEY CVE-2026-9256
CVE-2026-9256 · CWE-122 · Disclosed 2026-05-22

NGINX ngx_http_rewrite_module Heap Buffer Overflow via Overlapping PCRE Captures (PoolSlip)

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

Someone left the loading-dock gate cracked open, and a locksmith just published the master key on YouTube

CVE-2026-9256, publicly nicknamed nginx-poolslip, is a heap buffer overflow (CWE-122) in ngx_http_rewrite_module affecting NGINX Open Source 0.1.17 through 1.31.0 and NGINX Plus R32 through R36 plus 37.0.0. The flaw fires when a rewrite directive uses a regex pattern containing overlapping PCRE capture groups — the canonical example is ^/((.*))$ paired with a replacement string referencing both $1 and $2 in a redirect or arguments context. NGINX miscalculates the output buffer length after URI escaping, producing an out-of-bounds write into the worker process memory pool. An unauthenticated attacker over plain HTTP can crash the worker (DoS) or, with the public PoolSlip × Rift chain (exp_official.py), achieve reliable ASLR-independent remote code execution by partial-overwriting cleanup pointers — no address leak needed. Patches landed 2026-05-22 in NGINX OSS 1.30.2 / 1.31.1 and NGINX Plus R36 P5, R32 P7, R37.0.1.1.

F5's vendor score of 8.1 HIGH (CVSS:3.1) reflects AC:H — attack complexity is high because the specific overlapping-capture rewrite pattern is required. That was a fair call *before* the ASLR-bypass PoC dropped in July 2026. Now that exp_official.py demonstrates ASLR-independent RCE against a hardened Linux server using only ~300 HTTP requests, the practical attack complexity for code execution has dropped materially. The CVSS v4.0 re-score to 9.2 Critical acknowledges this. noisgate upgrades to 8.6 HIGH — the configuration prerequisite is real friction that prevents CRITICAL, but the demonstrated RCE chain, active exploitation, and NGINX's canonical role at the network edge push the score above the vendor baseline.

"NGINX edge proxy RCE with public ASLR bypass — config-dependent but actively exploited"
02 · The Attack Path

6 steps from start to impact.

STEP 01

Identify internet-facing NGINX with vulnerable version

The attacker queries Censys, Shodan, or FOFA for NGINX response headers disclosing a version in the 0.1.17–1.31.0 range. Censys surfaces roughly 5.7 million internet-exposed NGINX instances in the vulnerable range as of May 2026. Banner-grabbing is passive and trivial at scale.
Conditions required:
  • Target NGINX exposes version in Server header or error pages
Where this breaks in practice:
  • Many hardened deployments strip server_tokens; NGINX Plus by default still discloses major.minor
Detection/coverage: Shodan/Censys monitoring for your own assets; server_tokens off in nginx.conf reduces exposure
STEP 02

Probe for exploitable rewrite configuration

The attacker sends crafted URI paths designed to trigger overlapping-capture rewrite rules and observes responses. A 302 redirect whose Location header contains duplicated path segments confirms the pattern. Alternatively, a segfault-induced 502 confirms the overflow. This pattern — overlapping PCRE captures in redirect/args context — appears in SEO redirect blocks, URL canonicalization, and legacy migration configs. CyCognito estimates it is 'far from rare' but not default.
Conditions required:
  • NGINX config contains rewrite with overlapping PCRE captures referencing $1$2 in redirect or args context
Where this breaks in practice:
  • Not a default config — requires the specific nested-capture pattern; many sites use return 301 or try_files instead of regex rewrites
  • Configs using named captures ((?<name>...)) are NOT vulnerable
Detection/coverage: WAF signatures for nested-path-traversal patterns in URI; NGINX error log monitoring for worker segfaults (signal 11)
STEP 03

Trigger heap overflow for DoS

Approximately 40 warmup requests stabilize the heap layout of the NGINX worker process. A single crafted request then triggers the out-of-bounds write, crashing the worker. The master process respawns the worker, but sustained requests produce a crash loop — effective denial of service. No authentication, no special headers, just malformed URI paths. Tool: any HTTP client (curl, python-requests).
Conditions required:
  • Vulnerable rewrite rule is reachable
Where this breaks in practice:
  • Worker restarts are fast; sustained DoS requires continuous request stream
  • Rate limiting or connection limits can slow the attacker
Detection/coverage: Monitor error.log for signal 11 (SIGSEGV) and worker process exited on signal 11; correlate with 502 spikes
STEP 04

Heap leak via PoolSlip info-disclosure primitive

The PoolSlip overflow is used as an information-disclosure primitive: by carefully controlling the overwrite length, the attacker forces the worker to include adjacent heap data in the HTTP response (e.g., Location header or response body). This leaks heap pointers needed for the next stage. Approximately 1 request performs the leak. Tool: exp_official.py (y198nt / DepthFirstDisclosures).
Conditions required:
  • Worker has not yet crashed from the overflow (controlled overwrite)
  • Chaining with CVE-2026-42945 (NGINX Rift) — target must also be unpatched for that CVE
Where this breaks in practice:
  • If target patched CVE-2026-42945 (1.30.1 / 1.31.0) but not CVE-2026-9256, the ASLR-bypass chain breaks — DoS/blind overflow only
  • Precise heap grooming is fragile across different allocator configurations (glibc version, jemalloc, etc.)
Detection/coverage: Anomalous response sizes from NGINX — responses containing binary or unexpectedly long Location headers
STEP 05

ASLR-independent RCE via partial pointer overwrite

The exploit overwrites only the low 2 bytes of an existing limit_conn cleanup-handler pointer, leaving the ASLR-randomized high bytes intact. This makes the technique ASLR-independent — no full address brute-force required. The corrupted pointer redirects control flow to attacker-controlled heap data. Approximately 8 upload requests plus 16 connection-setup requests groom the heap, then 1 final request triggers the overwrite. The attacker gains code execution as the NGINX worker user (nginx / www-data). Tool: exp_official.py published on GitHub with Docker lab environment.
Conditions required:
  • Both CVE-2026-9256 and CVE-2026-42945 unpatched
  • Heap grooming succeeds for the target's glibc version (demonstrated on glibc-2.41)
Where this breaks in practice:
  • Worker runs as unprivileged user — post-exploitation requires local privilege escalation
  • Heap layout varies across NGINX compile options, modules loaded, and OS allocator
  • Exploit reliability is high but not 100% — occasional worker crash instead of clean RCE
Detection/coverage: EDR/auditd alerting on unexpected child processes spawned by nginx worker; file integrity monitoring on web roots
STEP 06

Post-exploitation: pivot from edge proxy

With code execution on the NGINX reverse proxy, the attacker occupies a man-in-the-middle position on all proxied traffic. They can inject JavaScript into responses, steal session cookies and credentials in transit, modify upstream requests, and pivot to backend application servers on internal networks that trust the proxy IP. In Kubernetes environments where NGINX Ingress Controller is compromised, the attacker can access cluster-internal services and potentially the Kubernetes API server.
Conditions required:
  • RCE achieved on NGINX worker
  • NGINX is deployed as a reverse proxy or ingress controller (canonical deployment)
Where this breaks in practice:
  • mTLS between proxy and backends limits credential theft
  • Network segmentation and zero-trust policies restrict lateral movement
  • Kubernetes RBAC limits Ingress Controller service account privileges
Detection/coverage: Network anomaly detection for unusual outbound connections from NGINX hosts; Kubernetes audit logs for unexpected API calls from ingress pods
03 · Compensating Control

1
HIGH 8.6→IGNORE 0.0
SEVERITY REDUCED
Patch NGINX to 1.30.2 (stable) or 1.31.1 (mainline) immediately — The definitive fix. This patches both CVE-2026-9256 and ensures you are not vulnerable to the PoolSlip × Rift chain. For NGINX Plus, upgrade to R36 P5, R32 P7, or R37.0.1.1. Given active exploitation and the noisgate HIGH verdict, deploy within 30 days per noisgate mitigation SLA. Prioritize internet-facing instances and ingress controllers.
2
HIGH 8.6→IGNORE 0.0
SEVERITY REDUCED
Rewrite overlapping PCRE captures to named captures — Replace patterns like ^/((.*))$ with ^/(?<path>.*)$ and reference $path instead of $1$2. This eliminates the vulnerable code path without upgrading NGINX. Audit your full config with nginx -T | grep -nE 'rewrite.*\$[0-9]+.*\$[0-9]+' or the nginx_poolslip_config_triage.py script from Penligent. Apply within 30 days if patching is delayed. Test redirects thoroughly after changes.
3
HIGH 8.6→HIGH 7.5
Confirm ASLR is enabled system-wide — Run cat /proc/sys/kernel/randomize_va_space — value must be 2 (full randomization). ASLR does NOT prevent the PoolSlip × Rift partial-overwrite chain, but it blocks older/simpler exploitation paths. If ASLR is disabled (value 0), the heap overflow becomes trivially exploitable for RCE without any chaining. This is a baseline hygiene check, not a standalone fix.
4
HIGH 8.6→HIGH 7.0
Deploy WAF rules to detect overlapping-capture probe patterns — Create WAF signatures matching URI paths with nested duplicate segments (e.g., /foo/foo patterns or excessively long path components) targeting locations known to have rewrite rules. This raises the bar for automated scanning but is bypassable by a determined attacker who can craft payloads that evade pattern matching. Deploy within 30 days.
5
HIGH 8.6→MEDIUM 6.5
SEVERITY REDUCED
Patch CVE-2026-42945 (NGINX Rift) if not already done — The ASLR-independent RCE chain requires both CVE-2026-9256 and CVE-2026-42945. If you patched to NGINX 1.30.1 or 1.31.0 for the Rift fix, you already broke the RCE chain — but you still face DoS from CVE-2026-9256. If you skipped the Rift patch entirely, you are exposed to the full RCE chain. Verify your version is at least 1.30.1/1.31.0 to break the chain, then prioritize the full 1.30.2/1.31.1 patch.
What doesn't work
  • Rate limiting alone — the full RCE exploit requires only ~300 requests total, well within normal traffic volumes for a production NGINX instance. Rate limiting may slow crash-loop DoS but will not prevent a targeted RCE attempt.
  • server_tokens off — hiding the NGINX version from response headers slows passive reconnaissance but does not prevent exploitation. Attackers can fingerprint NGINX behaviorally or simply spray the exploit against all NGINX targets.
  • Switching from PCRE to PCRE2 — CVE-2026-9256 affects the rewrite module's buffer calculation logic, not the regex engine itself. The bug is in how NGINX computes replacement string length from capture references, not in how PCRE evaluates the regex.
04 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationActive. Multiple sources (Indusface, SecurityBoulevard, CyCognito) confirm in-the-wild exploitation of CVE-2026-9256 as of late May 2026. Exploitation causes NGINX worker crash loops (DoS). RCE exploitation in the wild is unconfirmed but the full chain is public.
Proof-of-conceptPublic RCE exploit. exp_official.py by y198nt and DepthFirstDisclosures — chains PoolSlip (CVE-2026-9256) with Rift (CVE-2026-42945) for ASLR-independent RCE. Includes Docker lab for reproduction. Tracker repo: suominen/CVE-2026-9256. Config triage script: nginx_poolslip_config_triage.py (Penligent). Original discovery credited to Mufeed VH (Winfunc Research), Nebula Security, Vexera AI.
EPSS0.02697 (2.7%) — moderate probability of exploitation in the next 30 days. Given confirmed active exploitation, EPSS likely lags reality.
CISA KEVNot listed as of 2026-09-30. Active exploitation suggests KEV addition is likely if exploitation broadens.
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H = 8.1 HIGH. AC:H reflects the config-dependent trigger. CVSS v4.0 re-scored to 9.2 CRITICAL. The ASLR-bypass PoC arguably makes AC:H too generous — real-world complexity for RCE is lower than v3.1 suggests.
Affected versionsNGINX Open Source 0.1.17–1.30.1 and 1.31.0; NGINX Plus R32–R36 and 37.0.0. Note: 1.30.1 / 1.31.0 patched CVE-2026-42945 only — still vulnerable to CVE-2026-9256. 0.x branch EOL, no fix.
Fixed versionsNGINX OSS 1.30.2 (stable), 1.31.1 (mainline). NGINX Plus R36 P5, R32 P7, R37.0.1.1. Downstream: RHEL/CentOS, Debian, Ubuntu, Amazon Linux, Alpine all have backport packages. TuxCare fix tracked as CLSA-2026-1779714591.
Internet exposureCensys: ~5.7 million internet-facing NGINX instances in the vulnerable version range (VulnCheck, May 2026). CyCognito sector breakdown: Consumer Discretionary 27.7%, Information Technology 17.2% of observed vulnerable assets. Exploitable subset is smaller — config-dependent.
Disclosure timeline2026-05-22: F5 advisory + upstream patches released. 2026-07-05: PoolSlip × Rift ASLR-independent RCE PoC published. Active exploitation observed from late May 2026 onward.
Reporting researchersMufeed VH (Winfunc Research), Nebula Security, Vexera AI (original discovery). y198nt (ASLR-bypass chain, glibc-2.41 adaptation). DepthFirstDisclosures (Rift PoC component).

Sources.

  1. F5 / NGINX Advisory K000161377
  2. CyCognito Emerging Threat Analysis
  3. PoolSlip × Rift ASLR-Independent RCE PoC Archive
  4. CyberSecurityNews — nginx-poolslip writeup
  5. suominen/CVE-2026-9256 patch tracker (GitHub)
  6. Indusface — NGINX Active Exploitation
  7. Penligent HackingLabs — CVE-2026-9256 deep dive
  8. NGINX Official Security Advisories
05 · The Call

Final Verdict
= UNCHANGED to HIGH (8.6/10)

Why this verdict

  • ASLR bypass eliminates the key RCE barrier: The vendor's AC:H rating assumed ASLR would gate code execution, making DoS the primary real-world outcome. The public exp_official.py exploit demonstrates ASLR-independent RCE via partial pointer overwrite, requiring only ~300 HTTP requests against a fully hardened Linux server. This materially reduces the practical attack complexity for RCE and justifies upward pressure from 8.1.
  • Active exploitation with public tooling: In-the-wild exploitation is confirmed by multiple threat intelligence sources since May 2026. The full RCE chain, including Docker reproduction lab, is publicly available on GitHub. The combination of active exploitation and weaponized public exploit code increases urgency beyond what the vendor score conveys.
  • Role multiplier: NGINX is a canonical network edge component. The majority of NGINX deployments (estimated >60%) serve as reverse proxies, load balancers, API gateways, or Kubernetes Ingress Controllers at the network perimeter. This is not an incidental high-value role — it is the *primary* deployment pattern. RCE on an edge proxy gives the attacker a man-in-the-middle position on all proxied traffic (credential interception, response injection, session hijacking) plus pivot access to backend servers and internal networks. In Kubernetes, compromising the NGINX Ingress Controller puts the attacker at the cluster edge with potential access to the API server. Blast radius: host → network segment → backend tier → potentially domain/cluster. This floors the verdict at HIGH.
  • Configuration prerequisite provides genuine friction (prevents CRITICAL): The overlapping PCRE capture pattern (^/((.*))$ with $1$2 replacement) is required. While 'far from rare' in SEO redirects and URL canonicalization configs, it is NOT a default NGINX configuration. The attacker must find an instance with this specific rewrite pattern. This narrows the exploitable population from 5.7M internet-facing instances to a meaningful subset, providing real downward pressure that keeps this below CRITICAL despite the public RCE chain.
  • Chaining dependency adds fragility: The ASLR-independent RCE chain requires BOTH CVE-2026-9256 AND CVE-2026-42945 to be unpatched. Organizations that applied the earlier CVE-2026-42945 fix (1.30.1 / 1.31.0) broke the RCE chain — they face DoS only from CVE-2026-9256. This two-CVE dependency is an additional friction point that separates this from a single-shot CRITICAL.

Why not higher?

The overlapping PCRE capture pattern is a hard configuration prerequisite that is not present by default in NGINX. While common in SEO and migration configs, a significant majority of NGINX instances do not have this pattern, meaning the exploitable population is a fraction of the 5.7M exposed instances. Additionally, the full RCE chain requires both CVE-2026-9256 AND CVE-2026-42945 to be unpatched — sites that applied the earlier Rift fix are limited to DoS impact. These two real friction points prevent a CRITICAL rating despite the public ASLR-bypass exploit.

Why not lower?

NGINX is canonically deployed at the network edge — reverse proxy, load balancer, ingress controller — making it a high-value-role component by definition. A public, ASLR-independent RCE exploit exists and is actively exploited in the wild. Even with the configuration prerequisite, the blast radius when the chain succeeds on an edge proxy (traffic interception, backend pivot, potential cluster compromise) is too severe for MEDIUM. The floor for a canonical network-edge component with a working unauthenticated RCE chain is HIGH.

06 · Verification

Crowdsourced verification payload.

Run this script on each host running NGINX as a user with read access to the nginx binary and config directory (typically root or a member of the nginx group). Invoke with: sudo bash check_cve_2026_9256.sh. Exit code 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_cve_2026_9256.sh — CVE-2026-9256 (nginx-poolslip) detector
# Checks nginx version AND config for exploitable rewrite patterns.
# Exit: 0=PATCHED  1=VULNERABLE  2=UNKNOWN
set -uo pipefail

NGINX_BIN=$(command -v nginx 2>/dev/null || true)
if [[ -z "$NGINX_BIN" ]]; then
  echo "UNKNOWN - nginx binary not found in PATH"
  exit 2
fi

VER=$("$NGINX_BIN" -v 2>&1 | grep -oP 'nginx/\K[0-9]+\.[0-9]+\.[0-9]+' || true)
if [[ -z "$VER" ]]; then
  echo "UNKNOWN - could not parse nginx version"
  exit 2
fi
echo "[*] Detected nginx version: $VER"

IFS='.' read -r MAJ MIN PAT <<< "$VER"
PATCHED=0
if (( MAJ > 1 )); then
  PATCHED=1
elif (( MAJ == 1 )); then
  if (( MIN >= 32 )); then
    PATCHED=1
  elif (( MIN == 31 && PAT >= 1 )); then
    PATCHED=1
  elif (( MIN == 30 && PAT >= 2 )); then
    PATCHED=1
  fi
fi

if (( PATCHED == 1 )); then
  echo "PATCHED - nginx $VER is not in the affected range (CVE-2026-9256)"
  exit 0
fi

# Version is vulnerable — check config for exploitable pattern
echo "[!] nginx $VER is in the vulnerable range (0.1.17 – 1.31.0)"

CONFIG_DUMP=$($NGINX_BIN -T 2>/dev/null || true)
VULN_PATTERN=0
if [[ -n "$CONFIG_DUMP" ]]; then
  # Look for rewrite with multiple numeric backreferences ($1$2, etc.)
  HITS=$(echo "$CONFIG_DUMP" | grep -nE 'rewrite\s+.*\$[0-9]+.*\$[0-9]+' || true)
  # Also look for nested capture groups in rewrite
  NESTED=$(echo "$CONFIG_DUMP" | grep -nE 'rewrite\s+.*\(\(' || true)
  if [[ -n "$HITS" || -n "$NESTED" ]]; then
    VULN_PATTERN=1
    echo "[!!] Potentially exploitable rewrite patterns found:"
    [[ -n "$HITS" ]] && echo "$HITS"
    [[ -n "$NESTED" ]] && echo "$NESTED"
  else
    echo "[*] No overlapping-capture rewrite patterns detected in active config"
  fi
else
  echo "[*] Could not dump config (need root?) — skipping pattern check"
fi

if (( VULN_PATTERN == 1 )); then
  echo "VULNERABLE - nginx $VER with exploitable rewrite config (CVE-2026-9256)"
else
  echo "VULNERABLE - nginx $VER in affected range; no exploitable pattern found in config"
  echo "  NOTE: rewrite rules in dynamically included files may not have been checked"
fi
exit 1