Patching nginx doesn't close this one
CVE-2026-42945 NGINX rewrite module heap buffer overflow: bug mechanism, exploit primitives, MITRE mapping, and EDR telemetry blind spots in worker exploitation.
CVE-2026-42945. CVSS v3 base score 8.1, vector AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H. Heap buffer overflow in the NGINX ngx_http_rewrite_module affecting mainline 1.25.0 through 1.27.4 and stable 1.24.0 through 1.26.3. CWE-122. F5 shipped patches in 1.27.5 and 1.26.4. Pre-auth reachable on any server configuration that exposes a rewrite directive with capture group backreferences inside a location block - which is to say, most production deployments fronting application servers, reverse proxies, and CDN edges.
The bug class is a classic out-of-bounds heap write triggered by an undersized allocation in the rewrite engine’s variable expansion path. The rewrite module compiles regex patterns at config load and stores a ngx_http_script_regex_code_t structure that holds the expected capture count, the substitution length, and the offset table for backreference placement. At request time, when a URI matches and the substitution string contains backreferences like $1, $2, NGINX walks the compiled script codes and writes the resolved capture content into a freshly allocated buffer on the request pool.
The allocation size is computed at config parse from the literal substitution string plus a fixed per-backreference estimate. The estimate assumes each captured group will not exceed a bounded size relative to the original URI length. That assumption breaks when PCRE’s (?|...) branch reset groups, nested alternation, or specific quantifier patterns produce captures whose serialised length exceeds the pre-computed estimate after URL decoding and percent-encoding normalisation inside ngx_http_script_regex_start_code. The destination buffer is sized for the lower bound. The copy is performed against the actual, larger, decoded capture. The delta is the overflow.
What the attacker controls is the request URI. The bug is reachable any time a rewrite directive with a capture-backed substitution exists in the matched server or location context. Configurations that proxy to upstream services using rewrite ^/api/(.*)$ /v2/$1 break; are in scope. So are configurations using rewrite inside if blocks for header injection. The capture content is supplied entirely by the unauthenticated remote client. No authentication, no session, no specific Host header. The HTTP method is unconstrained. The trigger fits inside a single GET request line.
The overflow lands on the request pool - ngx_pool_t - which on a 64-bit Linux build is a chain of slab allocations served by NGINX’s pool allocator on top of glibc malloc. Adjacent objects in the pool at the time of overflow depend on request lifecycle ordering. Practical primitives observed in public analysis include overwrite of subsequent ngx_pool_cleanup_t function pointers, overwrite of ngx_http_request_t fields including the headers_out structure, and overwrite of pool allocator metadata that controls the next ngx_palloc return address. The cleanup pointer overwrite is the most direct path. ngx_pool_cleanup_t is a linked list of function pointers invoked at request finalisation. Corrupting the handler field and the data pointer yields controlled indirect call at request teardown.
From there the exploitation primitives are standard. The NGINX worker is a long-running process. PIE is enabled in distribution builds. Full ASLR applies. The attacker needs an info leak to resolve the worker base or libc base before the indirect call can be redirected. Two leak primitives are public. The first is a related length-confusion in the same code path that allows partial heap content to be reflected into a response header under a non-default add_header $captured_var configuration. The second is timing-based - measurable latency variance across requests that touch differently-laid pool chunks. The leak is configuration-dependent. The overflow itself is not.
Exploitation in the wild is confirmed. F5’s advisory references reports of targeted use against edge proxies in financial services environments prior to public disclosure. The behavior pattern observed - initial trigger from residential proxy IP ranges, post-exploit deployment of a memory-resident loader, lateral movement via SSRF through the compromised proxy into internal admin interfaces - aligns with tradecraft previously attributed to UNC-cluster activity tracked under multiple vendor names. MITRE mapping: T1190 exploit public-facing application for initial access, T1071.001 application-layer protocol over HTTP for command channel, T1055 process injection where the loader stages into the worker address space without writing to disk. The worker process running as nginx or www-data is the foothold. Privilege escalation requires a second bug. Lateral pivot through the proxy’s upstream connections often does not.
The telemetry picture is where defenders lose. NGINX runs in user space. The exploitation surface is entirely within the worker process. EDR sensors that monitor process creation, image loads, and registry activity see nothing during the exploitation itself - no new process, no DLL load, no script interpreter invocation. The worker forks at startup and serves indefinitely. There is no Sysmon Event ID 1 to fire. The pool cleanup hijack runs inside an already-resident process. Sysmon Event ID 10 - process access - only fires if the implant then opens handles into other processes. A well-written memory-resident implant that stays inside the worker and uses the worker’s existing network sockets generates no cross-process activity.
Network telemetry has more to work with but rarely uses it. The triggering URI is unusually long and contains percent-encoding patterns that exercise the vulnerable regex path. Reverse proxies and WAFs in front of NGINX can log the request line. Most do not alert on URI length distribution shifts or on percent-encoded byte sequences that deviate from baseline. The relevant primitives in Suricata or Zato are HTTP request line length thresholds and entropy analysis of the path component. Neither is enabled by default. Cloudflare’s managed rules include a generic long-URI rule that fires on requests above a configured threshold and would catch unrefined trigger payloads. Tuned exploitation payloads at or near the minimum trigger length pass.
NGINX’s own logs are partial. The default access.log format records the request line and is sufficient to reconstruct the trigger if the line is preserved. The error.log at default error level does not record rewrite-internal failures. At debug level the rewrite module logs capture content and substitution buffers - useful for post-incident forensics, useless for prevention since nobody runs production with debug logging. The pool allocator itself emits no diagnostics. A successful overflow that lands cleanly produces no log line at all. A failed overflow that corrupts the pool to an unparseable state crashes the worker. NGINX’s master process restarts the worker. The crash is recorded in error.log as worker process exited on signal 11. Repeated SIGSEGV from the same client IP is the strongest pre-compromise signal available. SOC teams that ingest NGINX error.log into a SIEM and correlate worker crashes against source IP have a detection. Teams that do not, do not.
EDR vendors with kernel-side syscall telemetry can build a secondary detection on the post-exploit behavior. The implant has to do something. If it spawns a child process - even sh -c - that fires standard process creation telemetry under the parent nginx worker. NGINX workers spawning shells is a strong anomaly signal in any reasonable baselining model. If the implant initiates outbound network connections to addresses not in the configured upstream pool, that diverges from the worker’s expected connection graph. CrowdStrike and SentinelOne both expose process-network correlation queryable from their threat hunting interfaces. The query parent_image_filename=nginx AND target_port NOT IN (configured_upstreams) is the hunt. The detection logic is straightforward. The instrumentation to support it is not always present.
The patch in 1.27.5 reworks the allocation sizing in ngx_http_script_regex_start_code to compute the destination buffer length from the actual decoded capture content rather than the pre-computed estimate. The fix is small. The patch diff is approximately forty lines centered on ngx_http_script.c. Backporting to older releases is mechanical. Distribution maintainers shipped updated packages within seventy-two hours of advisory publication. The exposure window for any organisation tracking F5 advisories closely is short. The exposure window for organisations running bundled NGINX inside vendor appliances - load balancers, WAF appliances, API gateways - is bounded by the vendor’s own patch cadence, which has historically run weeks to months behind upstream for this kind of bug.
Residual exposure after patching is non-trivial. NGINX is embedded in hundreds of commercial products. Identifying every instance of vulnerable NGINX inside an environment requires either software composition analysis against vendor SBOMs or active version banner enumeration. The Server header on responses reports the NGINX version when not stripped. Many production deployments strip the header for exactly this reason. Internal scanning against the SBOM is the reliable path. Vendor advisories from appliance manufacturers downstream of F5 are the dependency to track. The bug is patched. The exposure is until every embedded copy is patched too. That is months, not days.
Keep Reading
nginxNGINX ships emergency patch for HTTP/3 heap overflow
CVE-2026-42945 technical analysis: heap overflow in NGINX HTTP/3 HEADERS frame parsing, worker RCE primitive, telemetry gaps, and patch boundary.
exchange-serverThe IIS virtual directory that won't stop bleeding
Technical analysis of the Exchange Server zero-day, the frontend-to-backend trust boundary it abuses, and what fires in EDR and IIS telemetry.
NGINXAn NGINX worker just crashed in production
Board-level briefing on NGINX CVE-2026-42945: confirmed in-the-wild exploitation, edge exposure, control failure at runtime, and what must be established.
Stay in the loop
New writing delivered when it's ready. No schedule, no spam.