[PATCH 02 of 10] Rewrite: fixed incorrect initial escaping in "set"

Maxim Dounin mdounin at mdounin.ru
Mon May 18 16:41:45 UTC 2026


Hello!

On Sun, May 17, 2026 at 03:12:35AM +0300, Maxim Dounin wrote:

> # HG changeset patch
> # User Maxim Dounin <mdounin at mdounin.ru>
> # Date 1778973194 -10800
> #      Sun May 17 02:13:14 2026 +0300
> # Node ID 071c2e847b986bb7b133ff42c26f9aa2f55b102b
> # Parent  9aadc356492de0e61c8ee202c246c2353e8fbc83
> Rewrite: fixed incorrect initial escaping in "set".
> 
> Previously, the following configuration resulted in inconsistent escaping
> of the $temp variable in requests to "/a/..." and "/b/...":
> 
>     map $uri $foo {
>         ~(.*) 1;
>     }
> 
>     location /a/ {
>         set $temp $foo:$1;
>         return 200 $temp;
>     }
> 
>     location /b/ {
>         rewrite ^(.*) $1;
>         set $temp $foo:$1;
>         return 200 $temp;
>     }
> 
> In requests to "/a/..." the $1 capture contents were escaped when
> copying to the $temp variable due to e->quote being initially set in
> ngx_http_rewrite_handler().  And in requests to "/b/..." escaping was
> not used, since e->quote was cleared by ngx_http_script_regex_start_code()
> and ngx_http_script_regex_end_code().  Note well that in both cases $1
> comes from a regular expression in the map, and different behaviour here
> is clearly unexpected.
> 
> The "e->quote = 1;" initialization in ngx_http_rewrite_handler() was
> originally introduced in 485:4ebe09b07e30 (0.1.17) along with the new
> rewrite module, and had no effect at the time: e->quote was always set
> before being used.  It started to affect the module behaviour after the
> introduction of the "set" directive in 501:d4ea69372b94 (0.1.25) and
> variables support in "set" in 515:417a087c9c4d (0.1.32).
> 
> With this change, e->quote is no longer set in ngx_http_rewrite_handler(),
> resulting in consistent behaviour in all cases (and also matching the
> behaviour seen without an intermediate "set").
> 
> diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c
> --- a/src/http/modules/ngx_http_rewrite_module.c
> +++ b/src/http/modules/ngx_http_rewrite_module.c
> @@ -171,7 +171,6 @@ ngx_http_rewrite_handler(ngx_http_reques
>  
>      e->ip = rlcf->codes->elts;
>      e->request = r;
> -    e->quote = 1;
>      e->log = rlcf->log;
>      e->status = NGX_DECLINED;
>  

Looking more into this, I tend to think that this change might 
introduce security risks to configurations which rely on escaping 
being applied by "set".  A safer approach would be to make sure 
that escaping stays the same after a rewrite.  Patch below.

# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1779120864 -10800
#      Mon May 18 19:14:24 2026 +0300
# Node ID f7578d17fb54a54b85000a5aebef6c77748c2f14
# Parent  fb3ea1817a085ad147cf2f2fc6a87c01de243a69
Rewrite: fixed inconsistent escaping in "set".

Previously, the following configuration resulted in inconsistent escaping
of the $temp variable in requests to "/a/..." and "/b/...":

    location /a/ {
        if ($uri ~ (.*)) {
            set $temp $1;
        }
        return 200 $temp;
    }

    location /b/ {
        rewrite ^(.*) $1;
        if ($uri ~ (.*)) {
            set $temp $1;
        }
        return 200 $temp;
    }

In requests to "/a/..." the $1 capture contents were escaped when
copying to the $temp variable due to e->quote being initially set in
ngx_http_rewrite_handler().  And in requests to "/b/..." escaping was
not applied, since e->quote was cleared by ngx_http_script_regex_end_code().

With this change, the e->quote value set by ngx_http_script_regex_end_code()
matches the initial value set by ngx_http_rewrite_handler().  As a result,
escaping is now identical regardless of whether "set" is executed after
a rewrite or not.

Note that a better approach might be to avoid automatic escaping of
positional captures by "set" altogether.  However, this might put
existing configurations at risk if they rely on escaping being applied.
At the same time, if escaping is not desired, named captures can be used
instead.

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
@@ -1203,7 +1203,7 @@ ngx_http_script_regex_end_code(ngx_http_
 
     r = e->request;
 
-    e->quote = 0;
+    e->quote = 1;
     e->is_args = 0;
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,

-- 
Maxim Dounin
http://mdounin.ru/


More information about the nginx-devel mailing list