[ Reason ]
The update fixes three security vulnerabilities in nginx:
* CVE-2026-42533: a heap buffer overflow in the nginx script engine.
It can be triggered when a map directive performs regular-expression
matching and a string expression references captures modified by the
map, or when non-cacheable variables change between the script length
and copy passes.
* CVE-2026-56434: a use-after-free caused by duplicate finalization of
an HTTP subrequest. The issue is observable with SSI, proxy_pass and
proxy_buffering off when an upstream response causes the same
subrequest to be posted twice.
* CVE-2026-60005: an uninitialized memory read caused by stale regular
expression captures. ngx_http_regex_exec() could replace the
captures array without clearing r->ncaptures when the new regular
expression did not match. A subsequent unnamed capture could then
access uninitialized memory. The issue was introduced upstream by
commit 746fba0d79c6, first released in nginx 1.15.8.
The update also adds debian/tests/abicheck. This test is intended to
detect unintended changes to the public nginx module ABI. In
particular, it provides a safeguard for future stable updates: when
backporting and applying another patch, the test will detect changes to
the public headers if the package continues to declare the same nginx
ABI.
[ Impact ]
Without the update all three CVE-2026-42533 CVE-2026-56434 CVE-2026-60005
will be unfixed.
[ Tests ]
The package was tested using automated pipeline:
- https://salsa.debian.org/janmojzis/nginxtest/-/jobs/10252629
And also manuly on AMD64 version Debian trixie.
[ Risks ]
The fixes for CVE-2026-56434 and CVE-2026-60005 are small, direct
backports of upstream changes.
The CVE-2026-42533 fix is larger because upstream added fields to
ngx_http_script_engine_t and ngx_stream_script_engine_t. Applying that
layout change directly to trixie would break binary compatibility with
existing third-party nginx modules: the nginx module signature does not
cover these structures, so affected modules could load successfully and
then corrupt memory.
The new abicheck test reduces the risk of inadvertently breaking the nginx
module ABI, both in this update and in future stable updates. It verifies
that packages declaring the same nginx ABI continue to ship identical public
headers and detects changes to public structures or declarations that would
otherwise require an ABI transition and rebuild of dependent third-party
modules.
[ Checklist ]
[x] *all* changes are documented in the d/changelog
[x] I reviewed all changes and I approve them
[x] attach debdiff against the package in (old)stable
[x] the issue is verified as fixed in unstable
[ Changes ]
* 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.
[ Other info ]
* https://security-tracker.debian.org/tracker/CVE-2026-42533
* https://security-tracker.debian.org/tracker/CVE-2026-56434
* https://security-tracker.debian.org/tracker/CVE-2026-60005
A big thanks to Aron Xu for preparing the CVE-2026-42533.patch patch.
Debdiff:
diff -Nru nginx-1.26.3/debian/changelog nginx-1.26.3/debian/changelog
--- nginx-1.26.3/debian/changelog 2026-06-27 22:33:06.000000000 +0200
+++ nginx-1.26.3/debian/changelog 2026-09-04 19:02:15.000000000 +0200
@@ -1,3 +1,17 @@
+nginx (1.26.3-3+deb13u8) trixie; 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������ <janmojzis@debian.org> 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 01:00:00.000000000 +0100
+++ nginx-1.26.3/debian/patches/CVE-2026-42533.patch 2026-09-04 19:02:15.000000000 +0200
@@ -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 <ngx_http.h>
++#include <ngx_http.h>
++#include <ngx_http_script.hh>
+@@ -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 <ngx_http.h>
++#include <ngx_http.h>
++#include <ngx_http_script.hh>
+@@ -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 <ngx_http.h>
++#include <ngx_http.h>
++#include <ngx_http_script.hh>
+@@ -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 <ngx_http.h>
++#include <ngx_http.h>
++#include <ngx_http_script.hh>
+@@ -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 <ngx_http.h>
++#include <ngx_http.h>
++#include <ngx_http_script.hh>
+@@ -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 <ngx_http.h>
++#include <ngx_http.h>
++#include <ngx_http_script.hh>
+@@ -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 <ngx_http.h>
++#include <ngx_http.h>
++#include <ngx_http_script.hh>
+@@ -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 <ngx_http.h>
++#include <ngx_http.h>
++#include <ngx_http_script.hh>
+@@ -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 <ngx_stream.h>
++#include <ngx_stream.h>
++#include <ngx_stream_script.hh>
+@@ -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 01:00:00.000000000 +0100
+++ nginx-1.26.3/debian/patches/CVE-2026-56434.patch 2026-09-04 19:02:15.000000000 +0200
@@ -0,0 +1,66 @@
+Origin: https://github.com/nginx/nginx/commit/ddde692db11ab8238e9ca661007f64c9f6d764d2
+From: Roman Arutyunyan <arut@nginx.com>
+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 01:00:00.000000000 +0100
+++ nginx-1.26.3/debian/patches/CVE-2026-60005.patch 2026-09-04 19:02:15.000000000 +0200
@@ -0,0 +1,48 @@
+Origin: https://github.com/nginx/nginx/commit/b99f804ad38a60ceb07bc429598d5b2c4e70e336
+From: Pavel Pautov <p.pautov@f5.com>
+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 22:33:06.000000000 +0200
+++ nginx-1.26.3/debian/patches/series 2026-09-04 19:02:15.000000000 +0200
@@ -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 01:00:00.000000000 +0100
+++ nginx-1.26.3/debian/tests/abicheck 2026-09-04 19:02:15.000000000 +0200
@@ -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 22:33:06.000000000 +0200
+++ nginx-1.26.3/debian/tests/control 2026-09-04 19:02:15.000000000 +0200
@@ -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