nginx: backport fix for CVE-2026-9256

A heap memory buffer overflow might occur in a worker process when
using a configuration with overlapping captures in
ngx_http_rewrite_module, potentially resulting in arbitrary code
execution.

The buffer length calculation for static-length rewrite replacements
incorrectly used r->uri.data/r->uri.len for escape-size accounting
across all captures instead of the actual per-capture offsets into
r->captures_data.  This allowed overlapping captures to exceed the
allocated buffer.

Fix by iterating captures using the captures[] offsets into
captures_data rather than the full URI string.

Upstream-Status: Backport [https://github.com/nginx/nginx/commit/3f135ae2eb60ce376196c898a6c7cb4d774f7068]
CVE: CVE-2026-9256
Signed-off-by: Nelson Garcia <nelson831002@gmail.com>
Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
Nelson Garcia
2026-05-29 12:13:32 -04:00
committed by Anuj Mittal
parent 85aa67fa07
commit b0c2c648a1
2 changed files with 64 additions and 0 deletions
@@ -0,0 +1,63 @@
From 3f135ae2eb60ce376196c898a6c7cb4d774f7068 Mon Sep 17 00:00:00 2001
From: Roman Arutyunyan <arut@nginx.com>
Date: Thu, 22 May 2026 00:00:00 +0400
Subject: [PATCH] Rewrite: fix buffer overflow with overlapping captures.
A heap memory buffer overflow might occur in a worker process when using a
configuration with overlapping captures in ngx_http_rewrite_module,
potentially resulting in arbitrary code execution.
When calculating the buffer length for a rewrite replacement with static
length (code->lengths == NULL), the code incorrectly used r->uri.data and
r->uri.len for the escape size calculation across all captures, instead of
using the actual capture offsets into the captures data. This could allow
overlapping captures to cause a heap buffer overflow.
Reported by Mufeed VH of Winfunc Research.
CVE: CVE-2026-9256
Upstream-Status: Backport [https://github.com/nginx/nginx/commit/3f135ae2eb60ce376196c898a6c7cb4d774f7068]
Signed-off-by: Roman Arutyunyan <arut@nginx.com>
---
src/http/ngx_http_script.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -1037,6 +1037,8 @@ ngx_http_script_start_args_code(ngx_http_script_engine_t *e)
void
ngx_http_script_regex_start_code(ngx_http_script_engine_t *e)
{
+ int *cap;
+ u_char *p;
size_t len;
ngx_int_t rc;
ngx_uint_t n;
@@ -1143,15 +1145,19 @@ ngx_http_script_regex_start_code(ngx_http_script_engine_t *e)
if (code->lengths == NULL) {
e->buf.len = code->size;
- if (code->uri) {
- if (r->ncaptures && (r->quoted_uri || r->plus_in_uri)) {
- e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
- NGX_ESCAPE_ARGS);
- }
- }
+ cap = r->captures;
+ p = r->captures_data;
for (n = 2; n < r->ncaptures; n += 2) {
- e->buf.len += r->captures[n + 1] - r->captures[n];
+ e->buf.len += cap[n + 1] - cap[n];
+
+ if (code->uri) {
+ if (r->quoted_uri || r->plus_in_uri) {
+ e->buf.len += 2 * ngx_escape_uri(NULL, &p[cap[n]],
+ cap[n + 1] - cap[n],
+ NGX_ESCAPE_ARGS);
+ }
+ }
}
} else {
@@ -14,6 +14,7 @@ SRC_URI:append = " \
file://CVE-2026-42945.patch \
file://CVE-2026-42946-01.patch \
file://CVE-2026-42946-02.patch \
file://CVE-2026-9256.patch \
"
SRC_URI[sha256sum] = "77a2541637b92a621e3ee76776c8b7b40cf6d707e69ba53a940283e30ff2f55d"