Version in base suite: 1.26.3-3+deb13u7 Base version: nginx_1.26.3-3+deb13u7 Target version: nginx_1.26.3-3+deb13u8 Base file: /srv/ftp-master.debian.org/ftp/pool/main/n/nginx/nginx_1.26.3-3+deb13u7.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/n/nginx/nginx_1.26.3-3+deb13u8.dsc changelog | 14 patches/CVE-2026-42533.patch | 1889 +++++++++++++++++++++++++++++++++++++++++++ patches/CVE-2026-56434.patch | 66 + patches/CVE-2026-60005.patch | 48 + patches/series | 3 tests/abicheck | 91 ++ tests/control | 4 7 files changed, 2115 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpnapdvz6t/nginx_1.26.3-3+deb13u7.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpnapdvz6t/nginx_1.26.3-3+deb13u8.dsc: no acceptable signature found diff -Nru nginx-1.26.3/debian/changelog nginx-1.26.3/debian/changelog --- nginx-1.26.3/debian/changelog 2026-06-27 20:33:06.000000000 +0000 +++ nginx-1.26.3/debian/changelog 2026-09-04 17:02:15.000000000 +0000 @@ -1,3 +1,17 @@ +nginx (1.26.3-3+deb13u8) trixie-security; urgency=medium + + * d/t/abicheck add, detect unintended API changes in the nginx-dev + package by comparing header files with previous version + * d/p/CVE-2026-56434.patch add, backport fix for use-after-free when using + ngx_http_ssi_module (CVE-2026-56434) + * d/p/CVE-2026-60005.patch add, backport fix for memory disclosure + vulnerability when using ngx_http_slice_module (CVE-2026-60005) + * d/p/CVE-2026-42533.patch add, backport fix for buffer overflow + vulnerability when using map with regex (CVE-2026-42533) + A big thanks to Aron Xu for preparing the patch. + + -- Jan Mojžíš Fri, 04 Sep 2026 17:02:15 +0000 + nginx (1.26.3-3+deb13u7) trixie-security; urgency=high * Non-maintainer upload by the Security Team. diff -Nru nginx-1.26.3/debian/patches/CVE-2026-42533.patch nginx-1.26.3/debian/patches/CVE-2026-42533.patch --- nginx-1.26.3/debian/patches/CVE-2026-42533.patch 1970-01-01 00:00:00.000000000 +0000 +++ nginx-1.26.3/debian/patches/CVE-2026-42533.patch 2026-09-04 17:02:15.000000000 +0000 @@ -0,0 +1,1889 @@ +Description: CVE-2026-42533: script buffer overrun protection (ABI-preserving) + Backport of the upstream script buffer overrun protection series, reworked so + that no public structure layout changes and third-party modules built against + nginx-abi-1.26.3-1 keep working without a rebuild. + . + Upstream commits (nginx stable-1.30, released as 1.30.4): + ea47fabf5 Script: simplified copy capture codes. + 7ac67898b Script: buffer overrun protection. + 78950bdcd Access log: buffer overrun protection. + 326b17b00 Script: buffer overrun protection in direct script usage. + 97e40e59b Script: avoid garbage at the end of the result string + plus 42f8df65b Add missing bounds check in ngx_{http,stream}_compile_complex_value() + . + The ngx_http_proxy_v2_module hunk of 326b17b00 is dropped: that module does + not exist in 1.26.x. + . + Three deviations from upstream, all required to keep the ABI: + . + 1. Upstream adds "u_char *end" to ngx_http_script_engine_t and + ngx_stream_script_engine_t (and "ngx_int_t status" to the latter). The + new member is inserted after "pos", which shifts sp, buf, line, args, + status and request by one pointer (sizeof 88 -> 96 on amd64). Both + structures are part of the public API shipped in nginx-dev, and + NGX_MODULE_SIGNATURE does not cover them, so with --with-compat a module + built against the old header loads without complaint and then corrupts + memory. Verified: stock trixie libnginx-mod-http-set-misc (via + libnginx-mod-http-ndk) and libnginx-mod-nchan segfault the worker on the + first request when loaded into an nginx built with the upstream layout. + . + Instead the buffer end is derived from e->buf, which every script + evaluation entry point already sets to the buffer being written. + ngx_http_script_check_length() falls back to the previous unchecked + behaviour if e->pos does not point into e->buf, so a module driving the + engine in some other way is never failed spuriously. + . + 2. Consequently ngx_http_script_run() and ngx_stream_script_run() now set + e->buf, ngx_http_script_regex_end_code() truncates e->buf.len only after + the rewritten arguments have been copied, and the direct script users + (proxy, fastcgi, scgi, uwsgi, grpc, index, try_files) set e.buf.data and + e.buf.len where upstream sets e.end. The stream engine reports failure + via e.ip == ngx_stream_script_exit instead of a new status member; that + pointer is only ever set on error in the stream script engine. + . + 3. Upstream moves the value push out of ngx_http_script_complex_value_code() + into a new ngx_http_script_complex_value_end_code(). Modules that emit + ngx_http_script_complex_value_code() themselves and know nothing about the + new code (ngx_devel_kit, and hence set-misc, srcache and lua) would then + never push the value. The push is kept where it is and the end code only + corrects the length of the value already on the stack. + . + The implementation-only declarations are kept in private headers. No existing + public structure layout or function signature changes; + ngx_http_script_engine_t stays at 88 bytes and ngx_stream_script_engine_t at + 72 bytes on amd64, with every member at its previous offset. +Origin: backport, https://github.com/nginx/nginx/commit/b767540492e8c79a58bc26034d3bab2f708b7bd1 +Bug: https://my.f5.com/manage/s/article/K000162097 +Forwarded: not-needed +Last-Update: 2026-07-26 +--- +diff -Naur treeA/auto/modules treeC/auto/modules +--- a/auto/modules ++++ b/auto/modules +@@ -77,6 +77,7 @@ + src/http/ngx_http_cache.h \ + src/http/ngx_http_variables.h \ + src/http/ngx_http_script.h \ ++ src/http/ngx_http_script.hh \ + src/http/ngx_http_upstream.h \ + src/http/ngx_http_upstream_round_robin.h" + ngx_module_srcs="src/http/ngx_http.c \ +@@ -1058 +1059,2 @@ +- src/stream/ngx_stream_script.h \ ++ src/stream/ngx_stream_script.h \ ++ src/stream/ngx_stream_script.hh \ +diff -Naur treeA/src/http/modules/ngx_http_fastcgi_module.c treeC/src/http/modules/ngx_http_fastcgi_module.c +--- a/src/http/modules/ngx_http_fastcgi_module.c 2025-02-05 19:07:30.000000000 +0800 ++++ b/src/http/modules/ngx_http_fastcgi_module.c 2026-07-26 07:34:06.512868602 +0800 +@@ -10 +10,2 @@ +-#include ++#include ++#include +@@ -836,8 +836,8 @@ + { + off_t file_pos; + u_char ch, sep, *pos, *lowcase_key; +- size_t size, len, key_len, val_len, padding, +- allocated; ++ size_t size, len, params_len, ++ key_len, val_len, padding, allocated; + ngx_uint_t i, n, next, hash, skip_empty, header_params; + ngx_buf_t *b; + ngx_chain_t *cl, *body; +@@ -852,6 +852,7 @@ + ngx_http_script_len_code_pt lcode; + + len = 0; ++ params_len = 0; + header_params = 0; + ignored = NULL; + +@@ -891,8 +892,10 @@ + continue; + } + +- len += 1 + key_len + ((val_len > 127) ? 4 : 1) + val_len; ++ params_len += 1 + key_len + ((val_len > 127) ? 4 : 1) + val_len; + } ++ ++ len += params_len; + } + + if (flcf->upstream.pass_request_headers) { +@@ -1048,6 +1051,8 @@ + + e.ip = params->values->elts; + e.pos = b->last; ++ e.buf.data = b->last; ++ e.buf.len = params_len; + e.request = r; + e.flushed = 1; + +@@ -1080,6 +1085,12 @@ + continue; + } + ++ if (ngx_http_script_check_length(&e, 1 + ((val_len > 127) ? 4 : 1)) ++ != NGX_OK) ++ { ++ return NGX_ERROR; ++ } ++ + *e.pos++ = (u_char) key_len; + + if (val_len > 127) { +@@ -1098,12 +1109,22 @@ + } + e.ip += sizeof(uintptr_t); + ++ if (e.status) { ++ return NGX_ERROR; ++ } ++ + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "fastcgi param: \"%*s: %*s\"", + key_len, e.pos - (key_len + val_len), + val_len, e.pos - val_len); + } + ++ if (e.pos != e.buf.data + e.buf.len) { ++ ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, ++ "fastcgi request length mismatch"); ++ return NGX_ERROR; ++ } ++ + b->last = e.pos; + } + +diff -Naur treeA/src/http/modules/ngx_http_grpc_module.c treeC/src/http/modules/ngx_http_grpc_module.c +--- a/src/http/modules/ngx_http_grpc_module.c 2026-07-26 05:44:48.000000000 +0800 ++++ b/src/http/modules/ngx_http_grpc_module.c 2026-07-26 07:34:26.672893570 +0800 +@@ -708,8 +708,10 @@ + static ngx_int_t + ngx_http_grpc_create_request(ngx_http_request_t *r) + { +- u_char *p, *tmp, *key_tmp, *val_tmp, *headers_frame; +- size_t len, tmp_len, key_len, val_len, uri_len; ++ u_char *p, *tmp, *key_tmp, *val_tmp, *headers_frame, ++ *headers_end; ++ size_t len, headers_len, tmp_len, ++ key_len, val_len, uri_len; + uintptr_t escape; + ngx_buf_t *b; + ngx_uint_t i, next; +@@ -733,6 +735,8 @@ + len = sizeof(ngx_http_grpc_connection_start) - 1 + + sizeof(ngx_http_grpc_frame_t); /* headers frame */ + ++ headers_len = 0; ++ + /* :method header */ + + if (r->method == NGX_HTTP_GET || r->method == NGX_HTTP_POST) { +@@ -829,8 +833,8 @@ + return NGX_ERROR; + } + +- len += 1 + NGX_HTTP_V2_INT_OCTETS + key_len +- + NGX_HTTP_V2_INT_OCTETS + val_len; ++ headers_len += 1 + NGX_HTTP_V2_INT_OCTETS + key_len ++ + NGX_HTTP_V2_INT_OCTETS + val_len; + + if (tmp_len < key_len) { + tmp_len = key_len; +@@ -841,6 +845,8 @@ + } + } + ++ len += headers_len; ++ + if (glcf->upstream.pass_request_headers) { + part = &r->headers_in.headers.part; + header = part->elts; +@@ -1037,6 +1043,8 @@ + + le.ip = glcf->headers.lengths->elts; + ++ headers_end = b->last + headers_len; ++ + while (*(uintptr_t *) le.ip) { + + lcode = *(ngx_http_script_len_code_pt *) le.ip; +@@ -1061,16 +1069,40 @@ + continue; + } + ++ if (headers_end - b->last < 1) { ++ ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, ++ "no buffer space in grpc create request"); ++ return NGX_ERROR; ++ } ++ + *b->last++ = 0; + + e.pos = key_tmp; ++ e.buf.data = key_tmp; ++ e.buf.len = tmp_len; + + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + ++ if (e.status) { ++ return NGX_ERROR; ++ } ++ ++ key_len = e.pos - key_tmp; ++ ++ if (headers_end - b->last ++ < (ssize_t) (NGX_HTTP_V2_INT_OCTETS + key_len)) ++ { ++ ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, ++ "no buffer space in grpc create request"); ++ return NGX_ERROR; ++ } ++ + b->last = ngx_http_v2_write_name(b->last, key_tmp, key_len, tmp); + + e.pos = val_tmp; ++ e.buf.data = val_tmp; ++ e.buf.len = tmp_len; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; +@@ -1078,6 +1110,20 @@ + } + e.ip += sizeof(uintptr_t); + ++ if (e.status) { ++ return NGX_ERROR; ++ } ++ ++ val_len = e.pos - val_tmp; ++ ++ if (headers_end - b->last ++ < (ssize_t) (NGX_HTTP_V2_INT_OCTETS + val_len)) ++ { ++ ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, ++ "no buffer space in grpc create request"); ++ return NGX_ERROR; ++ } ++ + b->last = ngx_http_v2_write_value(b->last, val_tmp, val_len, tmp); + + #if (NGX_DEBUG) +diff -Naur treeA/src/http/modules/ngx_http_index_module.c treeC/src/http/modules/ngx_http_index_module.c +--- a/src/http/modules/ngx_http_index_module.c 2025-02-05 19:07:30.000000000 +0800 ++++ b/src/http/modules/ngx_http_index_module.c 2026-07-26 07:34:11.580874871 +0800 +@@ -10 +10,2 @@ +-#include ++#include ++#include +@@ -126,6 +126,7 @@ + name = NULL; + /* suppress MSVC warning */ + path.data = NULL; ++ e.status = 0; + + index = ilcf->indices->elts; + for (i = 0; i < ilcf->indices->nelts; i++) { +@@ -180,18 +181,29 @@ + } else { + e.ip = index[i].values->elts; + e.pos = name; ++ e.buf.data = name; ++ e.buf.len = allocated; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + } + ++ if (e.status) { ++ return NGX_HTTP_INTERNAL_SERVER_ERROR; ++ } ++ ++ if (ngx_http_script_check_length(&e, 1) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ + if (*name == '/') { +- uri.len = len - 1; ++ uri.len = e.pos - name; + uri.data = name; + return ngx_http_internal_redirect(r, &uri, &r->args); + } + ++ len = e.pos - name + 1; + path.len = e.pos - path.data; + + *e.pos = '\0'; +diff -Naur treeA/src/http/modules/ngx_http_log_module.c treeC/src/http/modules/ngx_http_log_module.c +--- a/src/http/modules/ngx_http_log_module.c 2025-02-05 19:07:30.000000000 +0800 ++++ b/src/http/modules/ngx_http_log_module.c 2026-07-26 07:32:24.544743382 +0800 +@@ -17,7 +17,7 @@ + typedef struct ngx_http_log_op_s ngx_http_log_op_t; + + typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf, +- ngx_http_log_op_t *op); ++ u_char *end, ngx_http_log_op_t *op); + + typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r, + uintptr_t data); +@@ -112,39 +112,42 @@ + static void ngx_http_log_flush_handler(ngx_event_t *ev); + + static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, +- ngx_http_log_op_t *op); ++ u_char *end, ngx_http_log_op_t *op); + static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf, +- ngx_http_log_op_t *op); ++ u_char *end, ngx_http_log_op_t *op); + static u_char *ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, +- ngx_http_log_op_t *op); ++ u_char *end, ngx_http_log_op_t *op); + static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, +- ngx_http_log_op_t *op); ++ u_char *end, ngx_http_log_op_t *op); + static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf, +- ngx_http_log_op_t *op); ++ u_char *end, ngx_http_log_op_t *op); + static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf, +- ngx_http_log_op_t *op); ++ u_char *end, ngx_http_log_op_t *op); + static u_char *ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf, +- ngx_http_log_op_t *op); +-static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r, +- u_char *buf, ngx_http_log_op_t *op); ++ u_char *end, ngx_http_log_op_t *op); ++static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf, ++ u_char *end, ngx_http_log_op_t *op); + static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, +- ngx_http_log_op_t *op); ++ u_char *end, ngx_http_log_op_t *op); + + static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf, + ngx_http_log_op_t *op, ngx_str_t *value, ngx_uint_t escape); + static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r, + uintptr_t data); + static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, +- ngx_http_log_op_t *op); ++ u_char *end, ngx_http_log_op_t *op); + static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size); + static size_t ngx_http_log_json_variable_getlen(ngx_http_request_t *r, + uintptr_t data); + static u_char *ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf, +- ngx_http_log_op_t *op); ++ u_char *end, ngx_http_log_op_t *op); + static size_t ngx_http_log_unescaped_variable_getlen(ngx_http_request_t *r, + uintptr_t data); + static u_char *ngx_http_log_unescaped_variable(ngx_http_request_t *r, +- u_char *buf, ngx_http_log_op_t *op); ++ u_char *buf, u_char *end, ngx_http_log_op_t *op); ++ ++static ngx_int_t ngx_http_log_check_length(ngx_http_request_t *r, ++ u_char *buf, u_char *end, size_t len); + + + static void *ngx_http_log_create_main_conf(ngx_conf_t *cf); +@@ -253,7 +256,7 @@ + static ngx_int_t + ngx_http_log_handler(ngx_http_request_t *r) + { +- u_char *line, *p; ++ u_char *line, *p, *end; + size_t len, size; + ssize_t n; + ngx_str_t val; +@@ -309,6 +312,8 @@ + } + } + ++ len += NGX_LINEFEED_SIZE; ++ + if (log[l].syslog_peer) { + + /* length of syslog's PRI and HEADER message parts */ +@@ -319,8 +324,6 @@ + goto alloc_line; + } + +- len += NGX_LINEFEED_SIZE; +- + buffer = log[l].file ? log[l].file->data : NULL; + + if (buffer) { +@@ -336,13 +339,18 @@ + if (len <= (size_t) (buffer->last - buffer->pos)) { + + p = buffer->pos; ++ end = p + len - NGX_LINEFEED_SIZE; + + if (buffer->event && p == buffer->start) { + ngx_add_timer(buffer->event, buffer->flush); + } + +- for (i = 0; i < log[l].format->ops->nelts; i++) { +- p = op[i].run(r, p, &op[i]); ++ for (i = 0; i < log[l].format->ops->nelts && p; i++) { ++ p = op[i].run(r, p, end, &op[i]); ++ } ++ ++ if (p == NULL) { ++ return NGX_ERROR; + } + + ngx_linefeed(p); +@@ -365,13 +373,18 @@ + } + + p = line; ++ end = line + len - NGX_LINEFEED_SIZE; + + if (log[l].syslog_peer) { + p = ngx_syslog_add_header(log[l].syslog_peer, line); + } + +- for (i = 0; i < log[l].format->ops->nelts; i++) { +- p = op[i].run(r, p, &op[i]); ++ for (i = 0; i < log[l].format->ops->nelts && p; i++) { ++ p = op[i].run(r, p, end, &op[i]); ++ } ++ ++ if (p == NULL) { ++ return NGX_ERROR; + } + + if (log[l].syslog_peer) { +@@ -770,7 +783,7 @@ + + + static u_char * +-ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf, ++ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf, u_char *end, + ngx_http_log_op_t *op) + { + size_t len; +@@ -779,6 +792,10 @@ + len = op->len; + data = op->data; + ++ if (ngx_http_log_check_length(r, buf, end, len) != NGX_OK) { ++ return NULL; ++ } ++ + while (len--) { + *buf++ = (u_char) (data & 0xff); + data >>= 8; +@@ -789,16 +806,25 @@ + + + static u_char * +-ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf, ++ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf, u_char *end, + ngx_http_log_op_t *op) + { ++ if (ngx_http_log_check_length(r, buf, end, op->len) != NGX_OK) { ++ return NULL; ++ } ++ + return ngx_cpymem(buf, (u_char *) op->data, op->len); + } + + + static u_char * +-ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) ++ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, u_char *end, ++ ngx_http_log_op_t *op) + { ++ if (ngx_http_log_check_length(r, buf, end, 1) != NGX_OK) { ++ return NULL; ++ } ++ + if (r->pipeline) { + *buf = 'p'; + } else { +@@ -810,24 +836,43 @@ + + + static u_char * +-ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) ++ngx_http_log_time(ngx_http_request_t *r, u_char *buf, u_char *end, ++ ngx_http_log_op_t *op) + { ++ if (ngx_http_log_check_length(r, buf, end, ngx_cached_http_log_time.len) ++ != NGX_OK) ++ { ++ return NULL; ++ } ++ + return ngx_cpymem(buf, ngx_cached_http_log_time.data, + ngx_cached_http_log_time.len); + } + + static u_char * +-ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) ++ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, u_char *end, ++ ngx_http_log_op_t *op) + { ++ if (ngx_http_log_check_length(r, buf, end, ngx_cached_http_log_iso8601.len) ++ != NGX_OK) ++ { ++ return NULL; ++ } ++ + return ngx_cpymem(buf, ngx_cached_http_log_iso8601.data, + ngx_cached_http_log_iso8601.len); + } + + static u_char * +-ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) ++ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, u_char *end, ++ ngx_http_log_op_t *op) + { + ngx_time_t *tp; + ++ if (ngx_http_log_check_length(r, buf, end, NGX_TIME_T_LEN + 4) != NGX_OK) { ++ return NULL; ++ } ++ + tp = ngx_timeofday(); + + return ngx_sprintf(buf, "%T.%03M", tp->sec, tp->msec); +@@ -835,12 +880,16 @@ + + + static u_char * +-ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf, ++ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf, u_char *end, + ngx_http_log_op_t *op) + { + ngx_time_t *tp; + ngx_msec_int_t ms; + ++ if (ngx_http_log_check_length(r, buf, end, NGX_TIME_T_LEN + 4) != NGX_OK) { ++ return NULL; ++ } ++ + tp = ngx_timeofday(); + + ms = (ngx_msec_int_t) +@@ -852,10 +901,15 @@ + + + static u_char * +-ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) ++ngx_http_log_status(ngx_http_request_t *r, u_char *buf, u_char *end, ++ ngx_http_log_op_t *op) + { + ngx_uint_t status; + ++ if (ngx_http_log_check_length(r, buf, end, NGX_INT_T_LEN) != NGX_OK) { ++ return NULL; ++ } ++ + if (r->err_status) { + status = r->err_status; + +@@ -874,9 +928,13 @@ + + + static u_char * +-ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf, ++ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf, u_char *end, + ngx_http_log_op_t *op) + { ++ if (ngx_http_log_check_length(r, buf, end, NGX_OFF_T_LEN) != NGX_OK) { ++ return NULL; ++ } ++ + return ngx_sprintf(buf, "%O", r->connection->sent); + } + +@@ -887,11 +945,15 @@ + */ + + static u_char * +-ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf, ++ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf, u_char *end, + ngx_http_log_op_t *op) + { + off_t length; + ++ if (ngx_http_log_check_length(r, buf, end, NGX_OFF_T_LEN) != NGX_OK) { ++ return NULL; ++ } ++ + length = r->connection->sent - r->header_size; + + if (length > 0) { +@@ -905,9 +967,13 @@ + + + static u_char * +-ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, ++ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, u_char *end, + ngx_http_log_op_t *op) + { ++ if (ngx_http_log_check_length(r, buf, end, NGX_OFF_T_LEN) != NGX_OK) { ++ return NULL; ++ } ++ + return ngx_sprintf(buf, "%O", r->request_length); + } + +@@ -968,21 +1034,39 @@ + + + static u_char * +-ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) ++ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, u_char *end, ++ ngx_http_log_op_t *op) + { ++ uintptr_t len; + ngx_http_variable_value_t *value; + + value = ngx_http_get_indexed_variable(r, op->data); + + if (value == NULL || value->not_found) { ++ if (ngx_http_log_check_length(r, buf, end, 1) != NGX_OK) { ++ return NULL; ++ } ++ + *buf = '-'; + return buf + 1; + } + + if (value->escape == 0) { ++ if (ngx_http_log_check_length(r, buf, end, value->len) != NGX_OK) { ++ return NULL; ++ } ++ + return ngx_cpymem(buf, value->data, value->len); + + } else { ++ len = ngx_http_log_escape(NULL, value->data, value->len); ++ ++ if (ngx_http_log_check_length(r, buf, end, value->len + len * 3) ++ != NGX_OK) ++ { ++ return NULL; ++ } ++ + return (u_char *) ngx_http_log_escape(buf, value->data, value->len); + } + } +@@ -1069,9 +1153,10 @@ + + + static u_char * +-ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf, ++ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf, u_char *end, + ngx_http_log_op_t *op) + { ++ uintptr_t len; + ngx_http_variable_value_t *value; + + value = ngx_http_get_indexed_variable(r, op->data); +@@ -1081,9 +1166,21 @@ + } + + if (value->escape == 0) { ++ if (ngx_http_log_check_length(r, buf, end, value->len) != NGX_OK) { ++ return NULL; ++ } ++ + return ngx_cpymem(buf, value->data, value->len); + + } else { ++ len = ngx_escape_json(NULL, value->data, value->len); ++ ++ if (ngx_http_log_check_length(r, buf, end, value->len + len) ++ != NGX_OK) ++ { ++ return NULL; ++ } ++ + return (u_char *) ngx_escape_json(buf, value->data, value->len); + } + } +@@ -1108,7 +1205,7 @@ + + static u_char * + ngx_http_log_unescaped_variable(ngx_http_request_t *r, u_char *buf, +- ngx_http_log_op_t *op) ++ u_char *end, ngx_http_log_op_t *op) + { + ngx_http_variable_value_t *value; + +@@ -1118,10 +1215,28 @@ + return buf; + } + ++ if (ngx_http_log_check_length(r, buf, end, value->len) != NGX_OK) { ++ return NULL; ++ } ++ + return ngx_cpymem(buf, value->data, value->len); + } + + ++static ngx_int_t ++ngx_http_log_check_length(ngx_http_request_t *r, u_char *buf, u_char *end, ++ size_t len) ++{ ++ if (end - buf < (ssize_t) len) { ++ ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, ++ "no buffer space in log script copy"); ++ return NGX_ERROR; ++ } ++ ++ return NGX_OK; ++} ++ ++ + static void * + ngx_http_log_create_main_conf(ngx_conf_t *cf) + { +diff -Naur treeA/src/http/modules/ngx_http_proxy_module.c treeC/src/http/modules/ngx_http_proxy_module.c +--- a/src/http/modules/ngx_http_proxy_module.c 2026-07-26 05:44:48.000000000 +0800 ++++ b/src/http/modules/ngx_http_proxy_module.c 2026-07-26 07:34:20.060885373 +0800 +@@ -10 +10,2 @@ +-#include ++#include ++#include +@@ -1235,7 +1235,7 @@ + static ngx_int_t + ngx_http_proxy_create_request(ngx_http_request_t *r) + { +- size_t len, uri_len, loc_len, body_len, ++ size_t len, uri_len, loc_len, body_len, headers_len, + key_len, val_len; + uintptr_t escape; + ngx_buf_t *b; +@@ -1289,6 +1289,8 @@ + escape = 0; + loc_len = 0; + unparsed_uri = 0; ++ body_len = 0; ++ headers_len = 0; + + if (plcf->proxy_lengths && ctx->vars.uri.len) { + uri_len = ctx->vars.uri.len; +@@ -1327,7 +1329,6 @@ + le.ip = plcf->body_lengths->elts; + le.request = r; + le.flushed = 1; +- body_len = 0; + + while (*(uintptr_t *) le.ip) { + lcode = *(ngx_http_script_len_code_pt *) le.ip; +@@ -1363,9 +1364,11 @@ + continue; + } + +- len += key_len + sizeof(": ") - 1 + val_len + sizeof(CRLF) - 1; ++ headers_len += key_len + sizeof(": ") - 1 + val_len + sizeof(CRLF) - 1; + } + ++ len += headers_len; ++ + + if (plcf->upstream.pass_request_headers) { + part = &r->headers_in.headers.part; +@@ -1457,6 +1460,8 @@ + + e.ip = headers->values->elts; + e.pos = b->last; ++ e.buf.data = b->last; ++ e.buf.len = headers_len; + e.request = r; + e.flushed = 1; + +@@ -1489,6 +1494,14 @@ + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + ++ if (e.status) { ++ return NGX_ERROR; ++ } ++ ++ if (ngx_http_script_check_length(&e, 2) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ + *e.pos++ = ':'; *e.pos++ = ' '; + + while (*(uintptr_t *) e.ip) { +@@ -1497,6 +1510,14 @@ + } + e.ip += sizeof(uintptr_t); + ++ if (e.status) { ++ return NGX_ERROR; ++ } ++ ++ if (ngx_http_script_check_length(&e, 2) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ + *e.pos++ = CR; *e.pos++ = LF; + } + +@@ -1547,6 +1568,8 @@ + if (plcf->body_values) { + e.ip = plcf->body_values->elts; + e.pos = b->last; ++ e.buf.data = b->last; ++ e.buf.len = body_len; + e.skip = 0; + + while (*(uintptr_t *) e.ip) { +@@ -1554,6 +1577,10 @@ + code((ngx_http_script_engine_t *) &e); + } + ++ if (e.status) { ++ return NGX_ERROR; ++ } ++ + b->last = e.pos; + } + +diff -Naur treeA/src/http/modules/ngx_http_rewrite_module.c treeC/src/http/modules/ngx_http_rewrite_module.c +--- a/src/http/modules/ngx_http_rewrite_module.c 2025-02-05 19:07:30.000000000 +0800 ++++ b/src/http/modules/ngx_http_rewrite_module.c 2026-07-26 05:56:35.168712725 +0800 +@@ -10 +10,2 @@ +-#include ++#include ++#include +@@ -966,10 +966,11 @@ + ngx_http_rewrite_value(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf, + ngx_str_t *value) + { +- ngx_int_t n; +- ngx_http_script_compile_t sc; +- ngx_http_script_value_code_t *val; +- ngx_http_script_complex_value_code_t *complex; ++ ngx_int_t n; ++ ngx_http_script_compile_t sc; ++ ngx_http_script_value_code_t *val; ++ ngx_http_script_complex_value_code_t *complex; ++ ngx_http_script_complex_value_end_code_t *complex_end; + + n = ngx_http_script_variables_count(value); + +@@ -1016,5 +1017,14 @@ + return NGX_CONF_ERROR; + } + ++ complex_end = ngx_http_script_add_code(lcf->codes, ++ sizeof(ngx_http_script_complex_value_end_code_t), ++ &complex); ++ if (complex_end == NULL) { ++ return NGX_CONF_ERROR; ++ } ++ ++ complex_end->code = ngx_http_script_complex_value_end_code; ++ + return NGX_CONF_OK; + } +diff -Naur treeA/src/http/modules/ngx_http_scgi_module.c treeC/src/http/modules/ngx_http_scgi_module.c +--- a/src/http/modules/ngx_http_scgi_module.c 2026-07-26 05:44:48.000000000 +0800 ++++ b/src/http/modules/ngx_http_scgi_module.c 2026-07-26 07:33:50.300848568 +0800 +@@ -11 +11,2 @@ +-#include ++#include ++#include +@@ -634,7 +634,7 @@ + { + off_t content_length_n; + u_char ch, sep, *key, *val, *lowcase_key; +- size_t len, key_len, val_len, allocated; ++ size_t len, params_len, key_len, val_len, allocated; + ngx_buf_t *b; + ngx_str_t content_length; + ngx_uint_t i, n, hash, skip_empty, header_params; +@@ -661,6 +661,7 @@ + + len = sizeof("CONTENT_LENGTH") + content_length.len + 1; + ++ params_len = 0; + header_params = 0; + ignored = NULL; + +@@ -698,8 +699,10 @@ + continue; + } + +- len += key_len + val_len + 1; ++ params_len += key_len + val_len + 1; + } ++ ++ len += params_len; + } + + if (scf->upstream.pass_request_headers) { +@@ -814,6 +817,8 @@ + + e.ip = params->values->elts; + e.pos = b->last; ++ e.buf.data = b->last; ++ e.buf.len = params_len; + e.request = r; + e.flushed = 1; + +@@ -852,6 +857,10 @@ + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + ++ if (e.status) { ++ return NGX_ERROR; ++ } ++ + #if (NGX_DEBUG) + val = e.pos; + #endif +@@ -859,6 +868,15 @@ + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + } ++ ++ if (e.status) { ++ return NGX_ERROR; ++ } ++ ++ if (ngx_http_script_check_length(&e, 1) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ + *e.pos++ = '\0'; + e.ip += sizeof(uintptr_t); + +@@ -866,6 +884,12 @@ + "scgi param: \"%s: %s\"", key, val); + } + ++ if (e.pos != e.buf.data + e.buf.len) { ++ ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, ++ "scgi request length mismatch"); ++ return NGX_ERROR; ++ } ++ + b->last = e.pos; + } + +diff -Naur treeA/src/http/modules/ngx_http_try_files_module.c treeC/src/http/modules/ngx_http_try_files_module.c +--- a/src/http/modules/ngx_http_try_files_module.c 2025-02-05 19:07:30.000000000 +0800 ++++ b/src/http/modules/ngx_http_try_files_module.c 2026-07-26 07:34:13.232876916 +0800 +@@ -10 +10,2 @@ +-#include ++#include ++#include +@@ -78,7 +78,7 @@ + static ngx_int_t + ngx_http_try_files_handler(ngx_http_request_t *r) + { +- size_t len, root, alias, reserve, allocated; ++ size_t len, root, alias, reserve, allocated, n; + u_char *p, *name; + ngx_str_t path, args; + ngx_uint_t test_dir; +@@ -162,8 +162,16 @@ + path.len = (name + tf->name.len - 1) - path.data; + + } else { ++ n = allocated; ++ ++ if (alias != NGX_MAX_SIZE_T_VALUE) { ++ n += (r->uri.len - alias); ++ } ++ + e.ip = tf->values->elts; + e.pos = name; ++ e.buf.data = name; ++ e.buf.len = n; + e.flushed = 1; + + while (*(uintptr_t *) e.ip) { +@@ -171,6 +179,14 @@ + code((ngx_http_script_engine_t *) &e); + } + ++ if (e.status) { ++ return NGX_HTTP_INTERNAL_SERVER_ERROR; ++ } ++ ++ if (ngx_http_script_check_length(&e, 1) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ + path.len = e.pos - path.data; + + *e.pos = '\0'; +diff -Naur treeA/src/http/modules/ngx_http_uwsgi_module.c treeC/src/http/modules/ngx_http_uwsgi_module.c +--- a/src/http/modules/ngx_http_uwsgi_module.c 2026-07-26 05:44:48.000000000 +0800 ++++ b/src/http/modules/ngx_http_uwsgi_module.c 2026-07-26 07:33:57.704857713 +0800 +@@ -12 +12,2 @@ +-#include ++#include ++#include +@@ -848,7 +848,7 @@ + ngx_http_uwsgi_create_request(ngx_http_request_t *r) + { + u_char ch, sep, *lowcase_key; +- size_t key_len, val_len, len, allocated; ++ size_t key_len, val_len, len, params_len, allocated; + ngx_uint_t i, n, hash, skip_empty, header_params; + ngx_buf_t *b; + ngx_chain_t *cl, *body; +@@ -861,6 +861,7 @@ + ngx_http_script_len_code_pt lcode; + + len = 0; ++ params_len = 0; + header_params = 0; + ignored = NULL; + +@@ -898,8 +899,10 @@ + continue; + } + +- len += 2 + key_len + 2 + val_len; ++ params_len += 2 + key_len + 2 + val_len; + } ++ ++ len += params_len; + } + + if (uwcf->upstream.pass_request_headers) { +@@ -1031,6 +1034,8 @@ + + e.ip = params->values->elts; + e.pos = b->last; ++ e.buf.data = b->last; ++ e.buf.len = params_len; + e.request = r; + e.flushed = 1; + +@@ -1063,12 +1068,24 @@ + continue; + } + ++ if (ngx_http_script_check_length(&e, 2) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ + *e.pos++ = (u_char) (key_len & 0xff); + *e.pos++ = (u_char) ((key_len >> 8) & 0xff); + + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + ++ if (e.status) { ++ return NGX_ERROR; ++ } ++ ++ if (ngx_http_script_check_length(&e, 2) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ + *e.pos++ = (u_char) (val_len & 0xff); + *e.pos++ = (u_char) ((val_len >> 8) & 0xff); + +@@ -1077,6 +1094,10 @@ + code((ngx_http_script_engine_t *) &e); + } + ++ if (e.status) { ++ return NGX_ERROR; ++ } ++ + e.ip += sizeof(uintptr_t); + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, +@@ -1085,6 +1106,12 @@ + val_len, e.pos - val_len); + } + ++ if (e.pos != e.buf.data + e.buf.len) { ++ ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, ++ "uwsgi request length mismatch"); ++ return NGX_ERROR; ++ } ++ + b->last = e.pos; + } + +diff -Naur treeA/src/http/ngx_http_script.c treeC/src/http/ngx_http_script.c +--- a/src/http/ngx_http_script.c 2026-07-26 05:44:48.000000000 +0800 ++++ b/src/http/ngx_http_script.c 2026-07-26 07:32:24.548743387 +0800 +@@ -10 +10,2 @@ +-#include ++#include ++#include +@@ -98,7 +98,12 @@ + code((ngx_http_script_engine_t *) &e); + } + +- *value = e.buf; ++ if (e.status) { ++ return NGX_ERROR; ++ } ++ ++ value->data = e.buf.data; ++ value->len = e.pos - e.buf.data; + + return NGX_OK; + } +@@ -150,7 +155,9 @@ + + for (i = 0; i < v->len; i++) { + if (v->data[i] == '$') { +- if (v->data[i + 1] >= '1' && v->data[i + 1] <= '9') { ++ if (i + 1 < v->len ++ && v->data[i + 1] >= '1' && v->data[i + 1] <= '9') ++ { + nc++; + + } else { +@@ -615,6 +622,7 @@ + ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value, + void *code_lengths, size_t len, void *code_values) + { ++ size_t n; + ngx_uint_t i; + ngx_http_script_code_pt code; + ngx_http_script_len_code_pt lcode; +@@ -636,26 +644,35 @@ + e.request = r; + e.flushed = 1; + ++ n = len; ++ + while (*(uintptr_t *) e.ip) { + lcode = *(ngx_http_script_len_code_pt *) e.ip; +- len += lcode(&e); ++ n += lcode(&e); + } + + +- value->len = len; +- value->data = ngx_pnalloc(r->pool, len); ++ value->len = n; ++ value->data = ngx_pnalloc(r->pool, n); + if (value->data == NULL) { + return NULL; + } + + e.ip = code_values; + e.pos = value->data; ++ e.buf = *value; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + } + ++ if (e.status) { ++ return NULL; ++ } ++ ++ value->len = e.pos + len - value->data; ++ + return e.pos; + } + +@@ -805,6 +822,46 @@ + } + + ++ngx_int_t ++ngx_http_script_check_length(ngx_http_script_engine_t *e, size_t len) ++{ ++ u_char *end; ++ ++ /* ++ * Upstream keeps the expected buffer end in a dedicated e->end field. ++ * Adding such a field would shift the offsets of all subsequent members ++ * of ngx_http_script_engine_t and break binary compatibility with ++ * modules built against previous versions of the header, so the bound ++ * is instead derived from e->buf, which already describes the buffer ++ * being written by every script evaluation entry point. ++ * ++ * If e->pos does not point into e->buf, the engine is being driven in a ++ * way we cannot reason about; the check is then skipped, leaving the ++ * previous (unchecked) behaviour rather than failing spuriously. ++ */ ++ ++ if (e->buf.data == NULL) { ++ return NGX_OK; ++ } ++ ++ end = e->buf.data + e->buf.len; ++ ++ if (e->pos < e->buf.data || e->pos > end) { ++ return NGX_OK; ++ } ++ ++ if (end - e->pos < (ssize_t) len) { ++ ngx_log_error(NGX_LOG_ALERT, e->request->connection->log, 0, ++ "no buffer space in script copy"); ++ e->ip = ngx_http_script_exit; ++ e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; ++ return NGX_ERROR; ++ } ++ ++ return NGX_OK; ++} ++ ++ + static ngx_int_t + ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, ngx_str_t *value, + ngx_uint_t last) +@@ -873,6 +930,11 @@ + p = e->pos; + + if (!e->skip) { ++ ++ if (ngx_http_script_check_length(e, code->len) != NGX_OK) { ++ return; ++ } ++ + e->pos = ngx_copy(p, e->ip + sizeof(ngx_http_script_copy_code_t), + code->len); + } +@@ -976,6 +1038,11 @@ + } + + if (value && !value->not_found) { ++ ++ if (ngx_http_script_check_length(e, value->len) != NGX_OK) { ++ return; ++ } ++ + p = e->pos; + e->pos = ngx_copy(p, value->data, value->len); + +@@ -1229,6 +1296,11 @@ + e->pos = dst; + + if (code->add_args && r->args.len) { ++ ++ if (ngx_http_script_check_length(e, r->args.len + 1) != NGX_OK) { ++ return; ++ } ++ + *e->pos++ = (u_char) (code->args ? '&' : '?'); + e->pos = ngx_copy(e->pos, r->args.data, r->args.len); + } +@@ -1259,13 +1331,25 @@ + } + + if (e->args) { +- e->buf.len = e->args - e->buf.data; ++ ++ /* ++ * note that e->buf.len is truncated only after the arguments are ++ * copied, as ngx_http_script_check_length() derives the end of the ++ * buffer from e->buf ++ */ + + if (code->add_args && r->args.len) { ++ ++ if (ngx_http_script_check_length(e, r->args.len + 1) != NGX_OK) { ++ return; ++ } ++ + *e->pos++ = '&'; + e->pos = ngx_copy(e->pos, r->args.data, r->args.len); + } + ++ e->buf.len = e->args - e->buf.data; ++ + r->args.len = e->pos - e->args; + r->args.data = e->args; + +@@ -1343,6 +1427,7 @@ + { + int *cap; + u_char *p; ++ size_t len; + ngx_uint_t n; + ngx_http_request_t *r; + ngx_http_script_copy_capture_code_t *code; +@@ -1358,17 +1443,17 @@ + if (n < r->ncaptures) { + + cap = r->captures; ++ len = cap[n + 1] - cap[n]; + + if ((e->is_args || e->quote) + && (e->request->quoted_uri || e->request->plus_in_uri)) + { +- p = r->captures_data; ++ p = r->captures_data + cap[n]; ++ ++ return len + 2 * ngx_escape_uri(NULL, p, len, NGX_ESCAPE_ARGS); + +- return cap[n + 1] - cap[n] +- + 2 * ngx_escape_uri(NULL, &p[cap[n]], cap[n + 1] - cap[n], +- NGX_ESCAPE_ARGS); + } else { +- return cap[n + 1] - cap[n]; ++ return len; + } + } + +@@ -1381,6 +1466,8 @@ + { + int *cap; + u_char *p, *pos; ++ size_t len; ++ uintptr_t escape; + ngx_uint_t n; + ngx_http_request_t *r; + ngx_http_script_copy_capture_code_t *code; +@@ -1398,16 +1485,27 @@ + if (n < r->ncaptures) { + + cap = r->captures; +- p = r->captures_data; ++ len = cap[n + 1] - cap[n]; ++ p = r->captures_data + cap[n]; + + if ((e->is_args || e->quote) + && (e->request->quoted_uri || e->request->plus_in_uri)) + { +- e->pos = (u_char *) ngx_escape_uri(pos, &p[cap[n]], +- cap[n + 1] - cap[n], +- NGX_ESCAPE_ARGS); ++ escape = 2 * ngx_escape_uri(NULL, p, len, NGX_ESCAPE_ARGS); ++ ++ if (ngx_http_script_check_length(e, len + escape) != NGX_OK) { ++ return; ++ } ++ ++ e->pos = (u_char *) ngx_escape_uri(pos, p, len, NGX_ESCAPE_ARGS); ++ + } else { +- e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]); ++ ++ if (ngx_http_script_check_length(e, len) != NGX_OK) { ++ return; ++ } ++ ++ e->pos = ngx_copy(pos, p, len); + } + } + +@@ -1484,6 +1582,7 @@ + } + + e->buf = value; ++ e->pos = value.data + value.len; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script fullname: \"%V\"", &value); +@@ -1797,6 +1896,28 @@ + } + + ++/* ++ * Upstream moves the push above into a separate "complex value end" code, so ++ * that the resulting length reflects what was actually written rather than ++ * the predicted length. Doing so would silently break modules which emit ++ * ngx_http_script_complex_value_code() themselves and do not know about the ++ * new code (notably ngx_devel_kit), as the value would never be pushed. ++ * Instead, the push is kept where it was and the end code merely corrects ++ * the length of the value already on the stack. ++ */ ++ ++void ++ngx_http_script_complex_value_end_code(ngx_http_script_engine_t *e) ++{ ++ e->ip += sizeof(ngx_http_script_complex_value_end_code_t); ++ ++ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, ++ "http script complex value end"); ++ ++ e->sp[-1].len = e->pos - e->buf.data; ++} ++ ++ + void + ngx_http_script_value_code(ngx_http_script_engine_t *e) + { +diff -Naur treeA/src/http/ngx_http_script.hh treeC/src/http/ngx_http_script.hh +--- /dev/null ++++ b/src/http/ngx_http_script.hh +@@ -0,0 +1,16 @@ ++#ifndef _NGX_HTTP_SCRIPT_HH_INCLUDED_ ++#define _NGX_HTTP_SCRIPT_HH_INCLUDED_ ++ ++ ++typedef struct { ++ ngx_http_script_code_pt code; ++} ngx_http_script_complex_value_end_code_t; ++ ++ ++ngx_int_t ngx_http_script_check_length(ngx_http_script_engine_t *e, ++ size_t len); ++ ++void ngx_http_script_complex_value_end_code(ngx_http_script_engine_t *e); ++ ++ ++#endif /* _NGX_HTTP_SCRIPT_HH_INCLUDED_ */ +diff -Naur treeA/src/stream/ngx_stream_log_module.c treeC/src/stream/ngx_stream_log_module.c +--- a/src/stream/ngx_stream_log_module.c 2025-02-05 19:07:30.000000000 +0800 ++++ b/src/stream/ngx_stream_log_module.c 2026-07-26 07:32:24.544743382 +0800 +@@ -17,7 +17,7 @@ + typedef struct ngx_stream_log_op_s ngx_stream_log_op_t; + + typedef u_char *(*ngx_stream_log_op_run_pt) (ngx_stream_session_t *s, +- u_char *buf, ngx_stream_log_op_t *op); ++ u_char *buf, u_char *end, ngx_stream_log_op_t *op); + + typedef size_t (*ngx_stream_log_op_getlen_pt) (ngx_stream_session_t *s, + uintptr_t data); +@@ -115,16 +115,19 @@ + static size_t ngx_stream_log_variable_getlen(ngx_stream_session_t *s, + uintptr_t data); + static u_char *ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf, +- ngx_stream_log_op_t *op); ++ u_char *end, ngx_stream_log_op_t *op); + static uintptr_t ngx_stream_log_escape(u_char *dst, u_char *src, size_t size); + static size_t ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s, + uintptr_t data); + static u_char *ngx_stream_log_json_variable(ngx_stream_session_t *s, +- u_char *buf, ngx_stream_log_op_t *op); ++ u_char *buf, u_char *end, ngx_stream_log_op_t *op); + static size_t ngx_stream_log_unescaped_variable_getlen(ngx_stream_session_t *s, + uintptr_t data); + static u_char *ngx_stream_log_unescaped_variable(ngx_stream_session_t *s, +- u_char *buf, ngx_stream_log_op_t *op); ++ u_char *buf, u_char *end, ngx_stream_log_op_t *op); ++ ++static ngx_int_t ngx_stream_log_check_length(ngx_stream_session_t *s, ++ u_char *buf, u_char *end, size_t len); + + + static void *ngx_stream_log_create_main_conf(ngx_conf_t *cf); +@@ -200,7 +203,7 @@ + static ngx_int_t + ngx_stream_log_handler(ngx_stream_session_t *s) + { +- u_char *line, *p; ++ u_char *line, *p, *end; + size_t len, size; + ssize_t n; + ngx_str_t val; +@@ -257,6 +260,8 @@ + } + } + ++ len += NGX_LINEFEED_SIZE; ++ + if (log[l].syslog_peer) { + + /* length of syslog's PRI and HEADER message parts */ +@@ -267,8 +272,6 @@ + goto alloc_line; + } + +- len += NGX_LINEFEED_SIZE; +- + buffer = log[l].file ? log[l].file->data : NULL; + + if (buffer) { +@@ -284,13 +287,18 @@ + if (len <= (size_t) (buffer->last - buffer->pos)) { + + p = buffer->pos; ++ end = p + len - NGX_LINEFEED_SIZE; + + if (buffer->event && p == buffer->start) { + ngx_add_timer(buffer->event, buffer->flush); + } + +- for (i = 0; i < log[l].format->ops->nelts; i++) { +- p = op[i].run(s, p, &op[i]); ++ for (i = 0; i < log[l].format->ops->nelts && p; i++) { ++ p = op[i].run(s, p, end, &op[i]); ++ } ++ ++ if (p == NULL) { ++ return NGX_ERROR; + } + + ngx_linefeed(p); +@@ -313,13 +321,18 @@ + } + + p = line; ++ end = p + len - NGX_LINEFEED_SIZE; + + if (log[l].syslog_peer) { + p = ngx_syslog_add_header(log[l].syslog_peer, line); + } + +- for (i = 0; i < log[l].format->ops->nelts; i++) { +- p = op[i].run(s, p, &op[i]); ++ for (i = 0; i < log[l].format->ops->nelts && p; i++) { ++ p = op[i].run(s, p, end, &op[i]); ++ } ++ ++ if (p == NULL) { ++ return NGX_ERROR; + } + + if (log[l].syslog_peer) { +@@ -663,7 +676,7 @@ + + + static u_char * +-ngx_stream_log_copy_short(ngx_stream_session_t *s, u_char *buf, ++ngx_stream_log_copy_short(ngx_stream_session_t *s, u_char *buf, u_char *end, + ngx_stream_log_op_t *op) + { + size_t len; +@@ -672,6 +685,10 @@ + len = op->len; + data = op->data; + ++ if (ngx_stream_log_check_length(s, buf, end, len) != NGX_OK) { ++ return NULL; ++ } ++ + while (len--) { + *buf++ = (u_char) (data & 0xff); + data >>= 8; +@@ -682,9 +699,13 @@ + + + static u_char * +-ngx_stream_log_copy_long(ngx_stream_session_t *s, u_char *buf, ++ngx_stream_log_copy_long(ngx_stream_session_t *s, u_char *buf, u_char *end, + ngx_stream_log_op_t *op) + { ++ if (ngx_stream_log_check_length(s, buf, end, op->len) != NGX_OK) { ++ return NULL; ++ } ++ + return ngx_cpymem(buf, (u_char *) op->data, op->len); + } + +@@ -745,22 +766,39 @@ + + + static u_char * +-ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf, ++ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf, u_char *end, + ngx_stream_log_op_t *op) + { ++ uintptr_t len; + ngx_stream_variable_value_t *value; + + value = ngx_stream_get_indexed_variable(s, op->data); + + if (value == NULL || value->not_found) { ++ if (ngx_stream_log_check_length(s, buf, end, 1) != NGX_OK) { ++ return NULL; ++ } ++ + *buf = '-'; + return buf + 1; + } + + if (value->escape == 0) { ++ if (ngx_stream_log_check_length(s, buf, end, value->len) != NGX_OK) { ++ return NULL; ++ } ++ + return ngx_cpymem(buf, value->data, value->len); + + } else { ++ len = ngx_stream_log_escape(NULL, value->data, value->len); ++ ++ if (ngx_stream_log_check_length(s, buf, end, value->len + len * 3) ++ != NGX_OK) ++ { ++ return NULL; ++ } ++ + return (u_char *) ngx_stream_log_escape(buf, value->data, value->len); + } + } +@@ -847,9 +885,10 @@ + + + static u_char * +-ngx_stream_log_json_variable(ngx_stream_session_t *s, u_char *buf, ++ngx_stream_log_json_variable(ngx_stream_session_t *s, u_char *buf, u_char *end, + ngx_stream_log_op_t *op) + { ++ uintptr_t len; + ngx_stream_variable_value_t *value; + + value = ngx_stream_get_indexed_variable(s, op->data); +@@ -859,9 +898,21 @@ + } + + if (value->escape == 0) { ++ if (ngx_stream_log_check_length(s, buf, end, value->len) != NGX_OK) { ++ return NULL; ++ } ++ + return ngx_cpymem(buf, value->data, value->len); + + } else { ++ len = ngx_escape_json(NULL, value->data, value->len); ++ ++ if (ngx_stream_log_check_length(s, buf, end, value->len + len) ++ != NGX_OK) ++ { ++ return NULL; ++ } ++ + return (u_char *) ngx_escape_json(buf, value->data, value->len); + } + } +@@ -887,7 +938,7 @@ + + static u_char * + ngx_stream_log_unescaped_variable(ngx_stream_session_t *s, u_char *buf, +- ngx_stream_log_op_t *op) ++ u_char *end, ngx_stream_log_op_t *op) + { + ngx_stream_variable_value_t *value; + +@@ -897,10 +948,28 @@ + return buf; + } + ++ if (ngx_stream_log_check_length(s, buf, end, value->len) != NGX_OK) { ++ return NULL; ++ } ++ + return ngx_cpymem(buf, value->data, value->len); + } + + ++static ngx_int_t ++ngx_stream_log_check_length(ngx_stream_session_t *s, u_char *buf, u_char *end, ++ size_t len) ++{ ++ if (end - buf < (ssize_t) len) { ++ ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0, ++ "no buffer space in log script copy"); ++ return NGX_ERROR; ++ } ++ ++ return NGX_OK; ++} ++ ++ + static void * + ngx_stream_log_create_main_conf(ngx_conf_t *cf) + { +diff -Naur treeA/src/stream/ngx_stream_script.c treeC/src/stream/ngx_stream_script.c +--- a/src/stream/ngx_stream_script.c 2025-02-05 19:07:30.000000000 +0800 ++++ b/src/stream/ngx_stream_script.c 2026-07-26 07:32:24.548743387 +0800 +@@ -10 +10,2 @@ +-#include ++#include ++#include +@@ -99,7 +99,12 @@ + code((ngx_stream_script_engine_t *) &e); + } + +- *value = e.buf; ++ if (e.ip == ngx_stream_script_exit) { ++ return NGX_ERROR; ++ } ++ ++ value->data = e.buf.data; ++ value->len = e.pos - e.buf.data; + + return NGX_OK; + } +@@ -151,7 +156,9 @@ + + for (i = 0; i < v->len; i++) { + if (v->data[i] == '$') { +- if (v->data[i + 1] >= '1' && v->data[i + 1] <= '9') { ++ if (i + 1 < v->len ++ && v->data[i + 1] >= '1' && v->data[i + 1] <= '9') ++ { + nc++; + + } else { +@@ -491,6 +498,7 @@ + ngx_stream_script_run(ngx_stream_session_t *s, ngx_str_t *value, + void *code_lengths, size_t len, void *code_values) + { ++ size_t n; + ngx_uint_t i; + ngx_stream_script_code_pt code; + ngx_stream_script_engine_t e; +@@ -512,26 +520,35 @@ + e.session = s; + e.flushed = 1; + ++ n = len; ++ + while (*(uintptr_t *) e.ip) { + lcode = *(ngx_stream_script_len_code_pt *) e.ip; +- len += lcode(&e); ++ n += lcode(&e); + } + + +- value->len = len; +- value->data = ngx_pnalloc(s->connection->pool, len); ++ value->len = n; ++ value->data = ngx_pnalloc(s->connection->pool, n); + if (value->data == NULL) { + return NULL; + } + + e.ip = code_values; + e.pos = value->data; ++ e.buf = *value; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_stream_script_code_pt *) e.ip; + code((ngx_stream_script_engine_t *) &e); + } + ++ if (e.ip == ngx_stream_script_exit) { ++ return NULL; ++ } ++ ++ value->len = e.pos + len - value->data; ++ + return e.pos; + } + +@@ -668,6 +685,34 @@ + } + + ++ngx_int_t ++ngx_stream_script_check_length(ngx_stream_script_engine_t *e, size_t len) ++{ ++ u_char *end; ++ ++ /* see the comment in ngx_http_script_check_length() */ ++ ++ if (e->buf.data == NULL) { ++ return NGX_OK; ++ } ++ ++ end = e->buf.data + e->buf.len; ++ ++ if (e->pos < e->buf.data || e->pos > end) { ++ return NGX_OK; ++ } ++ ++ if (end - e->pos < (ssize_t) len) { ++ ngx_log_error(NGX_LOG_ALERT, e->session->connection->log, 0, ++ "no buffer space in script copy"); ++ e->ip = ngx_stream_script_exit; ++ return NGX_ERROR; ++ } ++ ++ return NGX_OK; ++} ++ ++ + static ngx_int_t + ngx_stream_script_add_copy_code(ngx_stream_script_compile_t *sc, + ngx_str_t *value, ngx_uint_t last) +@@ -737,6 +782,11 @@ + p = e->pos; + + if (!e->skip) { ++ ++ if (ngx_stream_script_check_length(e, code->len) != NGX_OK) { ++ return; ++ } ++ + e->pos = ngx_copy(p, e->ip + sizeof(ngx_stream_script_copy_code_t), + code->len); + } +@@ -841,6 +891,11 @@ + } + + if (value && !value->not_found) { ++ ++ if (ngx_stream_script_check_length(e, value->len) != NGX_OK) { ++ return; ++ } ++ + p = e->pos; + e->pos = ngx_copy(p, value->data, value->len); + +@@ -894,6 +949,7 @@ + ngx_stream_script_copy_capture_len_code(ngx_stream_script_engine_t *e) + { + int *cap; ++ size_t len; + ngx_uint_t n; + ngx_stream_session_t *s; + ngx_stream_script_copy_capture_code_t *code; +@@ -908,7 +964,8 @@ + + if (n < s->ncaptures) { + cap = s->captures; +- return cap[n + 1] - cap[n]; ++ len = cap[n + 1] - cap[n]; ++ return len; + } + + return 0; +@@ -920,6 +977,7 @@ + { + int *cap; + u_char *p, *pos; ++ size_t len; + ngx_uint_t n; + ngx_stream_session_t *s; + ngx_stream_script_copy_capture_code_t *code; +@@ -936,8 +994,14 @@ + + if (n < s->ncaptures) { + cap = s->captures; +- p = s->captures_data; +- e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]); ++ len = cap[n + 1] - cap[n]; ++ p = s->captures_data + cap[n]; ++ ++ if (ngx_stream_script_check_length(e, len) != NGX_OK) { ++ return; ++ } ++ ++ e->pos = ngx_copy(pos, p, len); + } + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0, +@@ -1013,6 +1077,7 @@ + } + + e->buf = value; ++ e->pos = value.data + value.len; + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0, + "stream script fullname: \"%V\"", &value); +diff -Naur treeA/src/stream/ngx_stream_script.hh treeC/src/stream/ngx_stream_script.hh +--- /dev/null ++++ b/src/stream/ngx_stream_script.hh +@@ -0,0 +1,9 @@ ++#ifndef _NGX_STREAM_SCRIPT_HH_INCLUDED_ ++#define _NGX_STREAM_SCRIPT_HH_INCLUDED_ ++ ++ ++ngx_int_t ngx_stream_script_check_length(ngx_stream_script_engine_t *e, ++ size_t len); ++ ++ ++#endif /* _NGX_STREAM_SCRIPT_HH_INCLUDED_ */ diff -Nru nginx-1.26.3/debian/patches/CVE-2026-56434.patch nginx-1.26.3/debian/patches/CVE-2026-56434.patch --- nginx-1.26.3/debian/patches/CVE-2026-56434.patch 1970-01-01 00:00:00.000000000 +0000 +++ nginx-1.26.3/debian/patches/CVE-2026-56434.patch 2026-09-04 17:02:15.000000000 +0000 @@ -0,0 +1,66 @@ +Origin: https://github.com/nginx/nginx/commit/ddde692db11ab8238e9ca661007f64c9f6d764d2 +From: Roman Arutyunyan +Date: Mon, 29 Jun 2026 21:49:27 +0400 +Subject: [PATCH] Avoid duplicate subrequest finalization + +Previously, if a subrequest was posted twice, it could be finalized in +both calls, excessively reducing r->main->count and potentially leading +to a use-after-free. + +The fix is to avoid posting a request if it's already posted. Also, +as a hardening measure, r->write_event_handler is now reset to a no-op +handler during active subrequest finalization. + +The problem manifests itself in ngx_http_ssi_filter_module during +unbuffered proxying. If a subrequest is created for an SSI include +statement while the main request has some data postponed by another +include, this subrequest becomes double-posted when the main request +data is flushed. The first post comes from ngx_http_subrequest() and +the second one comes from ngx_http_postpone_filter(). In case of a +quick subrequest finalization, the above mentioned problem happens. + +Reported by P4P3R-HAK. +--- + src/http/ngx_http_request.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c +index a9573a620..c8dff236f 100644 +--- a/src/http/ngx_http_request.c ++++ b/src/http/ngx_http_request.c +@@ -2628,6 +2628,14 @@ ngx_http_post_request(ngx_http_request_t *r, ngx_http_posted_request_t *pr) + { + ngx_http_posted_request_t **p; + ++ for (p = &r->main->posted_requests; *p; p = &(*p)->next) { ++ if ((*p)->request == r) { ++ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ++ "http request already posted"); ++ return NGX_OK; ++ } ++ } ++ + if (pr == NULL) { + pr = ngx_palloc(r->pool, sizeof(ngx_http_posted_request_t)); + if (pr == NULL) { +@@ -2638,8 +2646,6 @@ ngx_http_post_request(ngx_http_request_t *r, ngx_http_posted_request_t *pr) + pr->request = r; + pr->next = NULL; + +- for (p = &r->main->posted_requests; *p; p = &(*p)->next) { /* void */ } +- + *p = pr; + + return NGX_OK; +@@ -2759,6 +2765,8 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) + + r->main->count--; + ++ r->write_event_handler = ngx_http_request_empty_handler; ++ + if (pr->postponed && pr->postponed->request == r) { + pr->postponed = pr->postponed->next; + } +-- +2.53.0 + diff -Nru nginx-1.26.3/debian/patches/CVE-2026-60005.patch nginx-1.26.3/debian/patches/CVE-2026-60005.patch --- nginx-1.26.3/debian/patches/CVE-2026-60005.patch 1970-01-01 00:00:00.000000000 +0000 +++ nginx-1.26.3/debian/patches/CVE-2026-60005.patch 2026-09-04 17:02:15.000000000 +0000 @@ -0,0 +1,48 @@ +Origin: https://github.com/nginx/nginx/commit/b99f804ad38a60ceb07bc429598d5b2c4e70e336 +From: Pavel Pautov +Date: Fri, 15 May 2026 00:48:50 -0700 +Subject: [PATCH] Fixed uninitialized memory read caused by stale regex + captures. + +When ngx_http_regex_exec() reallocates r->captures array, it doesn't update +r->ncaptures value, if regex didn't match. So the next use of unnamed regex +capture triggers uninitialized read and potential buffer overrun. + +This config demonstrates the issue: + map test $my_map { + volatile; + + ~mismatch(.*) 1; # reallocates r->captures in subrequests + + default ""; + } + + server { + location ~(.*) { # sets r->ncaptures + slice 50; + + # $1 will read from uninitialized memory in slice subrequests + proxy_set_header Test $my_map$1; + + proxy_set_header Range $slice_range; + proxy_pass http://backend; + } + } + +The issue was introduced by 746fba0d79c6. +--- + src/http/ngx_http_variables.c | 1 + + 1 file changed, 1 insertion(+) + +Index: nginx/src/http/ngx_http_variables.c +=================================================================== +--- nginx.orig/src/http/ngx_http_variables.c ++++ nginx/src/http/ngx_http_variables.c +@@ -2626,6 +2626,7 @@ ngx_http_regex_exec(ngx_http_request_t * + + if (r->captures == NULL || r->realloc_captures) { + r->realloc_captures = 0; ++ r->ncaptures = 0; + + r->captures = ngx_palloc(r->pool, len * sizeof(int)); + if (r->captures == NULL) { diff -Nru nginx-1.26.3/debian/patches/series nginx-1.26.3/debian/patches/series --- nginx-1.26.3/debian/patches/series 2026-06-27 20:32:00.000000000 +0000 +++ nginx-1.26.3/debian/patches/series 2026-09-04 17:02:15.000000000 +0000 @@ -19,3 +19,6 @@ FIX-HTTP2bomb.patch Upstream-limit-header-length-for-HTTP-2-and-gRPC.patch Charset-fixed-another-rare-buffer-overread-in-recode.patch +CVE-2026-56434.patch +CVE-2026-60005.patch +CVE-2026-42533.patch diff -Nru nginx-1.26.3/debian/tests/abicheck nginx-1.26.3/debian/tests/abicheck --- nginx-1.26.3/debian/tests/abicheck 1970-01-01 00:00:00.000000000 +0000 +++ nginx-1.26.3/debian/tests/abicheck 2026-09-04 17:02:15.000000000 +0000 @@ -0,0 +1,91 @@ +#!/bin/sh +set -e + +# This test compares the nginx-dev header files shipped by the package under +# test against all older versions currently available from the configured APT +# repositories. +# +# The goal is to detect unintended API changes. If no differences are found in +# the exported header files, the package is very likely ABI-safe for +# third-party modules built against previous versions, as they will continue to +# see the same public interface. +# +pkg=nginx-dev +localver="$(dpkg-query -W -f='${Version}\n' "$pkg")" + +local_abi="$( + sed -n 's/^nginx:abi=//p' \ + /usr/share/nginx/src/debian/libnginx-mod.abisubstvars +)" + +tmpdir="${AUTOPKGTEST_TMP:-/tmp}/download" +rm -rf "$tmpdir" +mkdir -p "$tmpdir" +cd "$tmpdir" + +headers_list="$tmpdir/headers-list" +trap 'rm -rf "$tmpdir"' EXIT INT HUP TERM + +versions="$( + apt-cache madison "$pkg" | + awk -F'|' -v pkg="$pkg" ' + { + name=$1 + ver=$2 + gsub(/^[ \t]+|[ \t]+$/, "", name) + gsub(/^[ \t]+|[ \t]+$/, "", ver) + if (name == pkg && ver != "") print ver + }' | + sort -u +)" + +for ver in $versions; do + echo "Downloading $pkg=$ver" + apt-get download "$pkg=$ver" + + deb="$(ls "${pkg}_${ver}"*.deb)" + unpackdir="$tmpdir/unpacked/$ver" + mkdir -p "$unpackdir" + dpkg-deb -R "$deb" "$unpackdir" +done + +failed=0 +compared=0 + +for ver in $versions; do + old_abi="$( + sed -n 's/^nginx:abi=//p' \ + "$tmpdir/unpacked/$ver/usr/share/nginx/src/debian/libnginx-mod.abisubstvars" + )" + + if [ "$local_abi" != "$old_abi" ]; then + echo "Skipping $ver ($old_abi): local $localver has $local_abi" + continue + fi + + echo "Comparing local version $localver against apt version $ver" + compared=$((compared + 1)) + + oldsrc="$tmpdir/unpacked/$ver/usr/share/nginx/src/src" + newsrc="/usr/share/nginx/src/src" + + find "$oldsrc" "$newsrc" -type f -name '*.h' | + sed "s#^$oldsrc/##; s#^$newsrc/##" | + sort -u > "$headers_list" + + while IFS= read -r f; do + diff -uN "$oldsrc/$f" "$newsrc/$f" || failed=1 + done < "$headers_list" +done + +if [ "$compared" -eq 0 ]; then + echo "All available versions have a different ABI, nothing to compare." + exit 77 +fi + +if [ "$failed" -ne 0 ]; then + echo "Available versions declare the same ABI but have a different ABI!" + exit 1 +fi + +exit 0 diff -Nru nginx-1.26.3/debian/tests/control nginx-1.26.3/debian/tests/control --- nginx-1.26.3/debian/tests/control 2026-06-27 20:25:23.000000000 +0000 +++ nginx-1.26.3/debian/tests/control 2026-09-04 17:02:15.000000000 +0000 @@ -149,3 +149,7 @@ Tests: ssi-module-test Restrictions: allow-stderr, isolation-container, needs-root, Depends: nginx, nginx-core, curl + +Tests: abicheck +Restrictions: allow-stderr skippable +Depends: nginx-dev