Bug 2480746 (CVE-2026-9256)

Summary: CVE-2026-9256 nginx: ngx_http_rewrite_module: code execution and denial of service
Product: [Other] Security Response Reporter: OSIDB Bzimport <bzimport>
Component: vulnerabilityAssignee: Product Security DevOps Team <prodsec-dev>
Status: NEW --- QA Contact:
Severity: high Docs Contact:
Priority: high    
Version: unspecifiedCC: bhg7698, cbrasic, kaycoth, rhel-process-autobot, watson-tool-maintainers
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: ---
Doc Text:
A flaw was found in the ngx_http_rewrite_module module of NGINX. When a rewrite directive uses a regex pattern with distinct, overlapping Perl-Compatible Regular Expression (PCRE) captures and a replacement string that references multiple such captures in a redirect or arguments context, an unauthenticated attacker can send crafted HTTP requests and cause a heap-based buffer overflow in the worker process, potentially allowing code execution or a denial of service by forcing the process to restart.
Story Points: ---
Clone Of: Environment:
Last Closed: Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On: 2481243    
Bug Blocks:    

Description OSIDB Bzimport 2026-05-22 15:01:18 UTC
NGINX Plus and NGINX Open Source have a vulnerability in the ngx_http_rewrite_module module. This vulnerability exists when a rewrite directive uses a regex pattern with distinct, overlapping Perl-Compatible Regular Expression (PCRE) captures (for example, ^/((.*))$) and a replacement string that references multiple such captures (for example, $1$2) in a redirect or arguments context. An unauthenticated attacker along with conditions beyond their control can exploit this vulnerability by sending crafted HTTP requests. This may cause a heap buffer overflow in the NGINX worker process leading to a restart. Additionally, attackers can execute code on systems with Address Space Layout Randomization (ASLR) disabled or when the attacker can bypass ASLR. 


Note: Software versions which have reached End of Technical Support (EoTS) are not evaluated.

Comment 3 errata-xmlrpc 2026-06-23 23:12:10 UTC
This issue has been addressed in the following products:

  Red Hat Enterprise Linux 9

Via RHSA-2026:28212 https://access.redhat.com/errata/RHSA-2026:28212

Comment 4 errata-xmlrpc 2026-06-24 09:50:10 UTC
This issue has been addressed in the following products:

  Red Hat Enterprise Linux 8

Via RHSA-2026:28921 https://access.redhat.com/errata/RHSA-2026:28921

Comment 5 errata-xmlrpc 2026-06-24 12:57:39 UTC
This issue has been addressed in the following products:

  Red Hat Enterprise Linux 9

Via RHSA-2026:28973 https://access.redhat.com/errata/RHSA-2026:28973

Comment 6 errata-xmlrpc 2026-06-24 16:11:14 UTC
This issue has been addressed in the following products:

  Red Hat Enterprise Linux 9

Via RHSA-2026:29151 https://access.redhat.com/errata/RHSA-2026:29151

Comment 7 errata-xmlrpc 2026-06-25 10:27:26 UTC
This issue has been addressed in the following products:

  Red Hat Enterprise Linux 10

Via RHSA-2026:29874 https://access.redhat.com/errata/RHSA-2026:29874

Comment 8 Carl Brasic 2026-07-01 16:04:58 UTC
The RHEL9 build shipped for RHSA-2026:29151 (`nginx-1.26.3-9.module+el9.8.0+24374+c0e15309.1`) has an ABI-breaking regression: any out-of-tree dynamic nginx module segfaults on the first request.

It comes from the `max_headers` patch (bundled in the same build, for the HTTP/2 DoS / CVE-2026-49975), which inserts a field into a public struct in `src/http/ngx_http_request.h`:

```diff
 typedef struct {
     ngx_list_t                        headers;
+    ngx_uint_t                        count;
     ngx_table_elt_t                  *host;
```

`ngx_http_headers_in_t` is embedded by value in `ngx_http_request_t`, so this shifts every subsequent field. A module built against the prior `1.26.3-9` respin reads `r->headers_in.*` at the wrong offsets → `worker process exited on signal 11`.

`NGX_MODULE_SIGNATURE` should refuse an incompatible module at load time, but it only encodes struct-affecting *build options*, not source struct changes, so it's byte-identical across both builds — the module loads, then crashes:

```console
$ for b in <prior-respin> 24374+c0e15309.1; do
    rpm2cpio nginx-core-*"$b"*.rpm | cpio --to-stdout -i --quiet ./usr/sbin/nginx \
      | strings | grep -m1 -E '^[0-9]+,[0-9]+,[0-9]+,'
  done
8,4,8,0011111111010111011111111111111111
8,4,8,0011111111010111011111111111111111   # identical, yet ABI differs
```

Two issues:
1. `max_headers` is an nginx 1.27 feature; an ABI-affecting struct change shouldn't land in a z-stream security build.
2. It ships under an unchanged NVR and unchanged module signature, so the safeguard meant to make this fail-load instead lets it segfault under live traffic.

Ubuntu hit the identical regression and fixed it in USN-8398-3 (reverted the CVE fix in -2, re-fixed in -3) — https://ubuntu.com/security/CVE-2026-49975#notes

Suggested fix: respin dropping the `max_headers` struct change from the 1.26 z-stream, or bump a signature-affecting identifier so mismatched modules are refused at load time.

Comment 9 Solarpepper 2026-07-03 09:31:29 UTC
Subject: Regression in nginx-2:1.20.1-28.el9_8.3.alma.1 — workers mass-aborting, Writing connections climbing to worker_connections limit
We'd like to report a production regression that appeared after this CVE-2026-9256 fix was backported into the EOL nginx:1.20 module stream on AlmaLinux 9.8.
Environment:

AlmaLinux 9.8, x86_64
nginx 1.20.1 module stream, upgraded manually 2026-06-29 23:17:37 directly from 2:1.20.1-22.el9_6.3.alma.2 to 2:1.20.1-28.el9_8.3.alma.1
worker_connections 5000;
Mixed HTTP/1.1 + HTTP/2 traffic (browsers, mobile app, search bots)
Backend via fastcgi_pass to php-fpm over unix sockets (not TCP)

Timeline:

Manual package upgrade: 2026-06-29 23:17:37
First anomaly in error.log: 2026-06-30 00:00:32
Recurring bursts throughout the night, increasing in frequency (~110 min apart → ~30 min apart by morning)
~09:00–11:00: site effectively unreachable, nginx-status "half-alive"
Manual dnf downgrade to 2:1.20.1-28.el9_8.2.alma.1 (the last build without this CVE fix) performed at 11:14 to resolve the incident — the systemd Main process exited, code=killed, status=9/KILL entries around 10:26 and 11:01 were from our own manual restart/kill attempts during this rollback, not an automated action. The downgrade immediately and fully resolved the issue, and it has not recurred since.

Symptom in error.log — recurring bursts of dozens of worker PIDs logging aborting in the same second:
2026/06/30 00:00:32 [alert] 842391#842391: aborting
2026/06/30 00:00:32 [alert] 842393#842393: aborting
... (13+ more PIDs, same timestamp)
followed by open socket #N left in connection M from the same/neighboring PIDs (workers not closing sockets gracefully before terminating), and continuously:
[alert] NNNNN#NNNNN: 5000 worker_connections are not enough
(~198,000 occurrences that day, matching nginx-status Writing climbing from single digits to 5,000–10,000 in a sawtooth pattern).
Ruled out:

No RPS/traffic increase around the incident (confirmed via monitoring — RPS flat, php-fpm RPS unchanged)
No cron/systemd-timer-triggered reload/restart in the affected windows
No OOM-kill events correlating with the abort bursts
No targeted attack pattern in access logs — the ~1,200 slow (>5s) HTTP/2 requests that day were spread across many unrelated IPs/user-agents with normal, fully-delivered response bodies, not the small-payload/near-zero-byte pattern of a Slowloris/HPACK-bomb exploit
Backend is unix-socket based, ruling out ephemeral port exhaustion

Working hypothesis: the mass, synchronous aborting bursts (no external trigger) look consistent with an internal timeout/shutdown mechanism related to this fix's Slowloris/HTTP2-hold mitigation misfiring on legitimate slow HTTP/2 transfers (large responses, mobile clients on poor connections) rather than an actual attack — causing workers to self-terminate under normal load. Downgrading to the pre-patch build resolved it with no config changes.
We're currently pinned to 2:1.20.1-28.el9_8.2.alma.1 (without this fix) to keep production stable. Happy to provide full config/logs if useful.

Comment 10 Carl Brasic 2026-07-14 13:28:18 UTC
Solarpepper, why did you flag needsinfo from me? Unclear what you are looking for.