Version in base suite: 1.26.3-3+deb13u7 Version in overlay suite: 1.26.3-3+deb13u9 Base version: nginx_1.26.3-3+deb13u9 Target version: nginx_1.26.3-3+deb13u10 Base file: /srv/ftp-master.debian.org/ftp/pool/main/n/nginx/nginx_1.26.3-3+deb13u9.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/n/nginx/nginx_1.26.3-3+deb13u10.dsc changelog | 17 +++ patches/CVE-2026-15176.patch | 50 +++++++++++ patches/CVE-2026-93479.patch | 105 ++++++++++++++++++++++++ patches/CVE-2026-95101.patch | 58 +++++++++++++ patches/CVE-2026-97205.patch | 183 +++++++++++++++++++++++++++++++++++++++++++ patches/CVE-2026-97629.patch | 41 +++++++++ patches/series | 5 + 7 files changed, 459 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpp2p35cmo/nginx_1.26.3-3+deb13u9.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpp2p35cmo/nginx_1.26.3-3+deb13u10.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-09-15 09:28:28.000000000 +0000 +++ nginx-1.26.3/debian/changelog 2026-10-15 01:08:48.000000000 +0000 @@ -1,3 +1,20 @@ +nginx (1.26.3-3+deb13u10) trixie-security; urgency=high + + * Backport security fixes from upstream 1.30.6: + - d/p/CVE-2026-15176.patch: reject URI to path mapping with alias + after a rewrite changed the URI. + - d/p/CVE-2026-93479.patch: protect reserved memory when evaluating + string expressions in HTTP and stream modules, adapting the fix + to the existing ABI-preserving script backport. + - d/p/CVE-2026-95101.patch: keep skipped HTTP/3 frame payload separate + from request body data, preserving nginx-dev ABI compatibility. + - d/p/CVE-2026-97629.patch: initialize all worker session ticket keys + during key rotation. + - d/p/CVE-2026-97205.patch: limit pending asynchronous operations + to prevent the request blocked counter from overflowing. + + -- Jan Mojžíš Thu, 15 Oct 2026 01:08:48 +0000 + nginx (1.26.3-3+deb13u9) trixie-security; urgency=medium * d/p/CVE-2026-42533.patch update: keep private script headers out of auto/modules' ngx_module_deps so third-party modules can be built diff -Nru nginx-1.26.3/debian/patches/CVE-2026-15176.patch nginx-1.26.3/debian/patches/CVE-2026-15176.patch --- nginx-1.26.3/debian/patches/CVE-2026-15176.patch 1970-01-01 00:00:00.000000000 +0000 +++ nginx-1.26.3/debian/patches/CVE-2026-15176.patch 2026-10-15 01:08:48.000000000 +0000 @@ -0,0 +1,50 @@ +Origin: https://github.com/nginx/nginx/commit/ce1da78900b07e72f37a25f55e6606220ac45902 +From e4f21028c0d8d0fae96adcdd1169bdee58477eb1 Mon Sep 17 00:00:00 2001 +From: Roman Arutyunyan +Date: Fri, 10 Jul 2026 20:10:12 +0400 +Subject: [PATCH] Avoid post-rewrite URI to path mapping with alias + +Previously, after a "rewrite" had changed the URI, and before a new +location was chosen, the new URI might not match the current location +prefix. This becomes a problem when the location uses "alias", which +is why normally such inconsistency is detected by checking the +r->valid_location flag. Meanwhile this flag only handles the +inconsistency when using the "break" directive or parameter. However +in absence of those, there's still an inconsistency window from URI +change up until the end of the current set of rewrite directives. +URI to path mapping within this window might result in a buffer +overflow if location's prefix was longer than the rewritten URI. + +The following example resulted in a buffer overflow with the request +"/foo/1": + +location /foo/ { + alias /bar/; + rewrite ^/foo/.*$ /x; + return 200 $request_filename; +} + +Alternatively, $request_filename might be used in access log format, +"set", "if", "add_header", etc. + +The fix is to reject URI mapping in ngx_http_map_uri_to_path() if the +r->uri_changed flag is set. + +CVE-2026-15176 +--- + src/http/ngx_http_core_module.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c +index c736d83..94f60cd 100644 +--- a/src/http/ngx_http_core_module.c ++++ b/src/http/ngx_http_core_module.c +@@ -1931,7 +1931,7 @@ ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *path, + + alias = clcf->alias; + +- if (alias && !r->valid_location) { ++ if (alias && (!r->valid_location || r->uri_changed)) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "\"alias\" cannot be used in location \"%V\" " + "where URI was rewritten", &clcf->name); diff -Nru nginx-1.26.3/debian/patches/CVE-2026-93479.patch nginx-1.26.3/debian/patches/CVE-2026-93479.patch --- nginx-1.26.3/debian/patches/CVE-2026-93479.patch 1970-01-01 00:00:00.000000000 +0000 +++ nginx-1.26.3/debian/patches/CVE-2026-93479.patch 2026-10-15 01:08:48.000000000 +0000 @@ -0,0 +1,105 @@ +Origin: https://github.com/nginx/nginx/commit/7abb1b4009fdf63e17a1721a932295714eb1fbb7 +From 65561e426175e0189f2e96e07459722c05b87d76 Mon Sep 17 00:00:00 2001 +From: Roman Arutyunyan +Date: Wed, 29 Jul 2026 16:57:59 +0400 +Subject: [PATCH] Script: reserved memory overrun protection in + ngx_http_script_run() + +In b76754049 buffer overrun protection in script was introduced. +However in ngx_http_script_run() data could still spill over to the +reserved area. This had no visible effects except the return value +which could extend beyond the maximum formatted string size. This +value is however currently unused in the nginx code. + +Later in a8289aa69 string length recalculation was implemented to +protect against buffer underwrite. Considering a possible spillover to +the reserved area, the final string size could become larger than the +allocated buffer size. This could later result in writing beyond +the buffer boundaries. Maximum buffer overflow is the size of the +reserved area. + +This could affect calculating document root from variables in HTTP +or using access logging in HTTP or Stream. In the case of access +logging a possible impact is limited by an off-by-one write of a null +byte. + +Reported by Matt Suiche of Tolmo Inc. + +CVE-2026-93479 + +Debian backport note: + nginx 1.26.3 uses the ABI-preserving CVE-2026-42533 backport, which + derives the writable buffer end from e.buf instead of adding e.end + to the public script engine structures. Set e.buf.len to the script + length without the reserved suffix, while allocating n + len bytes, + so the existing length checks protect that suffix in both HTTP and + stream. No public headers or structure layouts are changed. +--- + src/http/ngx_http_script.c | 7 ++++--- + src/stream/ngx_stream_script.c | 7 ++++--- + 2 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c +index 7614626..954588a 100644 +--- a/src/http/ngx_http_script.c ++++ b/src/http/ngx_http_script.c +@@ -645,7 +645,7 @@ ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value, + e.request = r; + e.flushed = 1; + +- n = len; ++ n = 0; + + while (*(uintptr_t *) e.ip) { + lcode = *(ngx_http_script_len_code_pt *) e.ip; +@@ -653,8 +653,8 @@ ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value, + } + + +- value->len = n; +- value->data = ngx_pnalloc(r->pool, n); ++ value->len = n + len; ++ value->data = ngx_pnalloc(r->pool, n + len); + if (value->data == NULL) { + return NULL; + } +@@ -662,6 +662,7 @@ ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value, + e.ip = code_values; + e.pos = value->data; + e.buf = *value; ++ e.buf.len = n; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; +diff --git a/src/stream/ngx_stream_script.c b/src/stream/ngx_stream_script.c +index 1ee924f..3ef2ddc 100644 +--- a/src/stream/ngx_stream_script.c ++++ b/src/stream/ngx_stream_script.c +@@ -521,7 +521,7 @@ ngx_stream_script_run(ngx_stream_session_t *s, ngx_str_t *value, + e.session = s; + e.flushed = 1; + +- n = len; ++ n = 0; + + while (*(uintptr_t *) e.ip) { + lcode = *(ngx_stream_script_len_code_pt *) e.ip; +@@ -529,8 +529,8 @@ ngx_stream_script_run(ngx_stream_session_t *s, ngx_str_t *value, + } + + +- value->len = n; +- value->data = ngx_pnalloc(s->connection->pool, n); ++ value->len = n + len; ++ value->data = ngx_pnalloc(s->connection->pool, n + len); + if (value->data == NULL) { + return NULL; + } +@@ -538,6 +538,7 @@ ngx_stream_script_run(ngx_stream_session_t *s, ngx_str_t *value, + e.ip = code_values; + e.pos = value->data; + e.buf = *value; ++ e.buf.len = n; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_stream_script_code_pt *) e.ip; diff -Nru nginx-1.26.3/debian/patches/CVE-2026-95101.patch nginx-1.26.3/debian/patches/CVE-2026-95101.patch --- nginx-1.26.3/debian/patches/CVE-2026-95101.patch 1970-01-01 00:00:00.000000000 +0000 +++ nginx-1.26.3/debian/patches/CVE-2026-95101.patch 2026-10-15 01:08:48.000000000 +0000 @@ -0,0 +1,58 @@ +Origin: https://github.com/nginx/nginx/commit/90b30edffea4f427608c36e3849643b6f9841bc4 +From 0d695d761629d70d7b6d4053b8557d6085e72557 Mon Sep 17 00:00:00 2001 +From: Vadim Zhestikov +Date: Wed, 22 Jul 2026 17:48:55 -0700 +Subject: [PATCH] HTTP/3: kept the skipped frame length separate from data + length + +ngx_http_v3_parse_data() stored the remaining length of a skipped +(unknown) frame in st->length -- the same field the request body +filter uses for the number of DATA payload bytes to pass on as +request body. When an unknown frame was split across parser +invocations, the skip was interrupted with st->length holding the +skip remainder; on the next buffer the body filter, which calls +the parser only while st->length == 0, treated that remainder as +request body. + +When proxying, this could result in sending unframed bytes, potentially +allowing for bypass of client_max_body_size, which is enforced only on +the DATA path, or an injection. + +The fix is to keep unknown frame payload in a separate st->skip counter. + +Reported by Hansol Lee of GOTROOT. + +CVE-2026-95101 + +Debian backport note: + Keep ngx_http_v3_parse_data_t unchanged for nginx-dev ABI compatibility. + Reuse st->type as the skip counter while in sw_skip: the unknown frame + type is no longer needed, and sw_type overwrites it for the next frame. + Keep st->length zero while skipping, as in the upstream fix. +--- + src/http/v3/ngx_http_v3_parse.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/http/v3/ngx_http_v3_parse.c b/src/http/v3/ngx_http_v3_parse.c +index 436765c..c10fbe6 100644 +--- a/src/http/v3/ngx_http_v3_parse.c ++++ b/src/http/v3/ngx_http_v3_parse.c +@@ -1831,6 +1831,9 @@ ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st, + st->type, st->length); + + if (st->type != NGX_HTTP_V3_FRAME_DATA && st->length > 0) { ++ /* reuse the frame type as the remaining skip length */ ++ st->type = st->length; ++ st->length = 0; + st->state = sw_skip; + break; + } +@@ -1840,7 +1843,7 @@ ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st, + + case sw_skip: + +- rc = ngx_http_v3_parse_skip(b, &st->length); ++ rc = ngx_http_v3_parse_skip(b, &st->type); + if (rc != NGX_DONE) { + return rc; + } diff -Nru nginx-1.26.3/debian/patches/CVE-2026-97205.patch nginx-1.26.3/debian/patches/CVE-2026-97205.patch --- nginx-1.26.3/debian/patches/CVE-2026-97205.patch 1970-01-01 00:00:00.000000000 +0000 +++ nginx-1.26.3/debian/patches/CVE-2026-97205.patch 2026-10-15 01:08:48.000000000 +0000 @@ -0,0 +1,183 @@ +Origin: https://github.com/nginx/nginx/commit/587c47aed19ddec799eee953a38837936e585b39 +From f79ec4991d5d16ebea4ca324e2813b33c8edf415 Mon Sep 17 00:00:00 2001 +From: Vadim Zhestikov +Date: Mon, 17 Aug 2026 09:19:46 -0700 +Subject: [PATCH] Limited the number of pending operations per request + +Each pending asynchronous operation holds a reference in +r->main->blocked, an 8-bit field, and the increments were not checked. +With 256 operations pending on a single request the counter wrapped to +zero, after which the request could be freed while those operations +still referenced its pool. This is the same overflow that 4ec67cf86 +addressed for r->main->count, and left unaddressed for r->main->blocked. + +Operations beyond the limit are now performed synchronously where a +synchronous path exists, and refused otherwise, so that the counter +cannot overflow. + +Reported by cyberlancer. + +CVE-2026-97205 + +Debian backport note: + Keep the public ngx_http_request.h unchanged for nginx-dev header + compatibility. Put NGX_HTTP_MAX_BLOCKED in a private .hh header. + The request structure and its 8-bit blocked counter remain unchanged. +--- + src/http/ngx_http_copy_filter_module.c | 37 ++++++++++++++++++++++++++ + src/http/ngx_http_file_cache.c | 13 +++++++-- + src/http/ngx_http_request.hh | 8 ++++++ + src/http/ngx_http_upstream.c | 7 +++++ + 4 files changed, 63 insertions(+), 2 deletions(-) + create mode 100644 src/http/ngx_http_request.hh + +diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c +index 8e5de2b..bde03cb 100644 +--- a/src/http/ngx_http_copy_filter_module.c ++++ b/src/http/ngx_http_copy_filter_module.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + + typedef struct { +@@ -87,6 +88,13 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) + ngx_output_chain_ctx_t *ctx; + ngx_http_core_loc_conf_t *clcf; + ngx_http_copy_filter_conf_t *conf; ++#if (NGX_HAVE_FILE_AIO) ++ ngx_output_chain_aio_pt aio_handler; ++#endif ++#if (NGX_THREADS) ++ ngx_int_t (*thread_handler)(ngx_thread_task_t *task, ++ ngx_file_t *file); ++#endif + + c = r->connection; + +@@ -140,10 +148,39 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) + + #if (NGX_HAVE_FILE_AIO || NGX_THREADS) + ctx->aio = r->aio; ++ ++#if (NGX_HAVE_FILE_AIO) ++ aio_handler = ctx->aio_handler; ++#endif ++#if (NGX_THREADS) ++ thread_handler = ctx->thread_handler; ++#endif ++ ++ /* ++ * each pending operation holds a reference in r->main->blocked; ++ * with the counter close to its limit the file is read ++ * synchronously instead, so that it cannot overflow ++ */ ++ ++ if (r->main->blocked >= NGX_HTTP_MAX_BLOCKED) { ++#if (NGX_HAVE_FILE_AIO) ++ ctx->aio_handler = NULL; ++#endif ++#if (NGX_THREADS) ++ ctx->thread_handler = NULL; ++#endif ++ } + #endif + + rc = ngx_output_chain(ctx, in); + ++#if (NGX_HAVE_FILE_AIO) ++ ctx->aio_handler = aio_handler; ++#endif ++#if (NGX_THREADS) ++ ctx->thread_handler = thread_handler; ++#endif ++ + if (ctx->in == NULL) { + r->buffered &= ~NGX_HTTP_COPY_BUFFERED; + +diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c +index 5209f00..39b7214 100644 +--- a/src/http/ngx_http_file_cache.c ++++ b/src/http/ngx_http_file_cache.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + + +@@ -440,6 +441,10 @@ ngx_http_file_cache_lock(ngx_http_request_t *r, ngx_http_cache_t *c) + return NGX_HTTP_CACHE_SCARCE; + } + ++ if (r->main->blocked >= NGX_HTTP_MAX_BLOCKED) { ++ return NGX_HTTP_CACHE_SCARCE; ++ } ++ + c->waiting = 1; + + if (c->wait_time == 0) { +@@ -692,7 +697,9 @@ ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c) + + #if (NGX_HAVE_FILE_AIO) + +- if (clcf->aio == NGX_HTTP_AIO_ON && ngx_file_aio) { ++ if (clcf->aio == NGX_HTTP_AIO_ON && ngx_file_aio ++ && r->main->blocked < NGX_HTTP_MAX_BLOCKED) ++ { + n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool); + + if (n != NGX_AGAIN) { +@@ -717,7 +724,9 @@ ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c) + + #if (NGX_THREADS) + +- if (clcf->aio == NGX_HTTP_AIO_THREADS) { ++ if (clcf->aio == NGX_HTTP_AIO_THREADS ++ && r->main->blocked < NGX_HTTP_MAX_BLOCKED) ++ { + c->file.thread_task = c->thread_task; + c->file.thread_handler = ngx_http_cache_thread_handler; + c->file.thread_ctx = r; +diff --git a/src/http/ngx_http_request.hh b/src/http/ngx_http_request.hh +new file mode 100644 +index 0000000..2f26692 +--- /dev/null ++++ b/src/http/ngx_http_request.hh +@@ -0,0 +1,8 @@ ++#ifndef _NGX_HTTP_REQUEST_HH_INCLUDED_ ++#define _NGX_HTTP_REQUEST_HH_INCLUDED_ ++ ++ ++#define NGX_HTTP_MAX_BLOCKED 250 ++ ++ ++#endif /* _NGX_HTTP_REQUEST_HH_INCLUDED_ */ +diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c +index 70c3b46..6da1043 100644 +--- a/src/http/ngx_http_upstream.c ++++ b/src/http/ngx_http_upstream.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + + #if (NGX_HTTP_CACHE) +@@ -3950,6 +3951,12 @@ ngx_http_upstream_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) + task->event.data = r; + task->event.handler = ngx_http_upstream_thread_event_handler; + ++ if (r->main->blocked >= NGX_HTTP_MAX_BLOCKED) { ++ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ++ "too many operations pending"); ++ return NGX_ERROR; ++ } ++ + if (ngx_thread_task_post(tp, task) != NGX_OK) { + return NGX_ERROR; + } diff -Nru nginx-1.26.3/debian/patches/CVE-2026-97629.patch nginx-1.26.3/debian/patches/CVE-2026-97629.patch --- nginx-1.26.3/debian/patches/CVE-2026-97629.patch 1970-01-01 00:00:00.000000000 +0000 +++ nginx-1.26.3/debian/patches/CVE-2026-97629.patch 2026-10-15 01:08:48.000000000 +0000 @@ -0,0 +1,41 @@ +Origin: https://github.com/nginx/nginx/commit/fdedba031bf1ad6a80c61b1aec1418d1a87ae296 +From 1e89174288ae362b4562e5085e5253cca43d8486 Mon Sep 17 00:00:00 2001 +From: Vadim Zhestikov +Date: Wed, 22 Jul 2026 16:48:37 -0700 +Subject: [PATCH] SSL: synced all session ticket keys to the worker process + +The per-worker ticket key mirror is allocated with three slots +(ngx_array_push_n(keys, 3)), matching the shared memory +ticket_keys[3] array and the decrypt callback, which scans all +keys->nelts slots by key name. Key rotation, however, synced +only two slots from shared memory, leaving the third slot's +name, hmac_key, and aes_key uninitialized. + +A ticket whose key name matched the uninitialized slot (which +holds unspecified pool memory, all zero in the best case) could +therefore be HMAC-verified and decrypted with uninitialized key +material, allowing a forged session. + +Sync all keys->nelts slots, as ngx_ssl_ticket_keys_cleanup() +already assumes. + +Reported by PhiNode Labs. + +CVE-2026-97629 +--- + src/event/ngx_event_openssl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c +index f12c4b8..2cb4ff4 100644 +--- a/src/event/ngx_event_openssl.c ++++ b/src/event/ngx_event_openssl.c +@@ -4845,7 +4845,7 @@ ngx_ssl_rotate_ticket_keys(SSL_CTX *ssl_ctx, ngx_log_t *log) + /* sync keys to the worker process memory */ + + ngx_memcpy(keys->elts, cache->ticket_keys, +- 2 * sizeof(ngx_ssl_ticket_key_t)); ++ keys->nelts * sizeof(ngx_ssl_ticket_key_t)); + + ngx_shmtx_unlock(&shpool->mutex); + diff -Nru nginx-1.26.3/debian/patches/series nginx-1.26.3/debian/patches/series --- nginx-1.26.3/debian/patches/series 2026-09-04 17:02:15.000000000 +0000 +++ nginx-1.26.3/debian/patches/series 2026-10-15 01:08:48.000000000 +0000 @@ -22,3 +22,8 @@ CVE-2026-56434.patch CVE-2026-60005.patch CVE-2026-42533.patch +CVE-2026-15176.patch +CVE-2026-93479.patch +CVE-2026-95101.patch +CVE-2026-97629.patch +CVE-2026-97205.patch