[PATCH] Fixed positional captures with cloned subrequests after non-match
Maxim Dounin
mdounin at mdounin.ru
Sun Aug 2 20:10:49 UTC 2026
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1785701313 -10800
# Sun Aug 02 23:08:33 2026 +0300
# Node ID da23d6e6186c5a11b082d894d0107d90761d8079
# Parent 42952827f5a9cc7cf589844bcb6afd1eedd13d50
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
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