[nginx] Fixed positional captures with cloned subrequests after ...

Maxim Dounin mdounin at mdounin.ru
Fri Aug 14 06:13:54 UTC 2026


details:   http://freenginx.org/hg/nginx/rev/e5cc09d2beb3
branches:  
changeset: 9582:e5cc09d2beb3
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Fri Aug 14 09:05:29 2026 +0300
description:
Fixed positional captures with cloned subrequests after non-match.

In 7427:81d49f85afed, the r->realloc_captures flag was introduced, to
facilitate use of positional captures with cloned subrequests, as used
by proxy_cache_background_update and the slice module.  The flag,
however, was only used to trigger a new allocation of r->captures, and
it contained uninitialized if a regular expression was not matched.  As
a result, if a regular expression was executed in a cloned subrequest
and not matched, and then a positional capture was used, it might refer
to arbitrary memory, such as in the following configuration (known as
CVE-2026-60005, though security impact is questionable):

    map $uri $map {
        ~(not-matched) 1;
    }

    location ~ /regex/(foo) {
        proxy_pass ...
        proxy_cache ...
        proxy_cache_background_update on;
        proxy_set_header Foo $map:$1;
    }

The fix is to actually copy r->captures contents to the new allocation,
so positional captures properly refer to the last matched regular
expression.

See also:
https://github.com/nginx/nginx/commit/0cca8e055a2d909f1a00c2071665b502ec2fe94c

diffstat:

 src/http/ngx_http_variables.c |  11 +++++++++--
 1 files changed, 9 insertions(+), 2 deletions(-)

diffs (30 lines):

diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -2657,6 +2657,7 @@ ngx_http_regex_compile(ngx_conf_t *cf, n
 ngx_int_t
 ngx_http_regex_exec(ngx_http_request_t *r, ngx_http_regex_t *re, ngx_str_t *s)
 {
+    int                        *captures;
     ngx_int_t                   rc, index;
     ngx_uint_t                  i, n, len;
     ngx_http_variable_value_t   vv;
@@ -2670,10 +2671,16 @@ ngx_http_regex_exec(ngx_http_request_t *
         if (r->captures == NULL || r->realloc_captures) {
             r->realloc_captures = 0;
 
-            r->captures = ngx_palloc(r->pool, len * sizeof(int));
-            if (r->captures == NULL) {
+            captures = ngx_pcalloc(r->pool, len * sizeof(int));
+            if (captures == NULL) {
                 return NGX_ERROR;
             }
+
+            if (r->captures) {
+                ngx_memcpy(captures, r->captures, len * sizeof(int));
+            }
+
+            r->captures = captures;
         }
 
     } else {


More information about the nginx-devel mailing list