From 475732a3f9dfe82fc2ecdb0a7426083c9c1ee965 Mon Sep 17 00:00:00 2001
From: Roman Arutyunyan <arut@nginx.com>
Date: Thu, 14 May 2026 17:47:42 +0400
Subject: [PATCH 1/2] Rewrite: harden escape flags control

Following 2046b45aa0c6, this change introduces better control of memory
allocation flags for escaped values.  Notably:

- The e->is_args flag is now explicitly reset on rewrite start.
  If the flag was set prior to rewrite start, then buffer overflow
  could happen before 2046b45aa0c6.

- The le->is_args flag value is now copied from e->is_args when
  calculating complex value length for "if" and "set" directives.
  If e->is_args was set, but le->is_args was not, then buffer overflow
  could happen before 2046b45aa0c6.
---
 src/http/ngx_http_script.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c
index 2ea611373..3018efe13 100644
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -1183,6 +1183,7 @@ ngx_http_script_regex_start_code(ngx_http_script_engine_t *e)
         return;
     }
 
+    e->is_args = 0;
     e->quote = code->redirect;
 
     e->pos = e->buf.data;
@@ -1769,6 +1770,7 @@ ngx_http_script_complex_value_code(ngx_http_script_engine_t *e)
     le.ip = code->lengths->elts;
     le.line = e->line;
     le.request = e->request;
+    le.is_args = e->is_args;
     le.quote = e->quote;
 
     for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
-- 
2.54.0


From ca4f92a27464ae6c2082245e4f67048c633aa032 Mon Sep 17 00:00:00 2001
From: Roman Arutyunyan <arut@nginx.com>
Date: Thu, 14 May 2026 18:42:18 +0400
Subject: [PATCH 2/2] Rewrite: fix buffer overflow with overlapping captures

When the rewrite replacement string had no variables, but had
overlapping captures, the length of the allocated buffer could be
smaller than the replacement string.  This could happen either
when the "redirect" parameter is specified, or when arguments are
present in the replacement string.

The following configurations resulted in heap buffer overflow when
using URI "/++++++++++++++++++++++++++++++":

    location / {
        rewrite ^/((.*))$ http://127.0.0.1:8080/$1$2 redirect;
        return 200 foo;
    }

    location / {
        rewrite ^/((.*))$ http://127.0.0.1:8080/?$1$2;
        return 200 foo;
    }

Reported by Mufeed VH of Winfunc Research.
---
 src/http/ngx_http_script.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c
index 3018efe13..8f7b548cc 100644
--- 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 {
-- 
2.54.0

