Version in base suite: 1.64.0-1.1+deb13u1 Base version: nghttp2_1.64.0-1.1+deb13u1 Target version: nghttp2_1.64.0-1.1+deb13u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/n/nghttp2/nghttp2_1.64.0-1.1+deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/n/nghttp2/nghttp2_1.64.0-1.1+deb13u2.dsc changelog | 6 patches/CVE-2026-58055.patch | 287 +++++++++++++++++++++++++++++++++++++++++++ patches/series | 1 3 files changed, 294 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpxqdle51t/nghttp2_1.64.0-1.1+deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpxqdle51t/nghttp2_1.64.0-1.1+deb13u2.dsc: no acceptable signature found diff -Nru nghttp2-1.64.0/debian/changelog nghttp2-1.64.0/debian/changelog --- nghttp2-1.64.0/debian/changelog 2026-04-15 15:04:15.000000000 +0000 +++ nghttp2-1.64.0/debian/changelog 2026-09-03 21:11:23.000000000 +0000 @@ -1,3 +1,9 @@ +nghttp2 (1.64.0-1.1+deb13u2) trixie; urgency=medium + + * CVE-2026-58055 (Closes: #1140917) + + -- Moritz Mühlenhoff Thu, 03 Sep 2026 23:11:23 +0200 + nghttp2 (1.64.0-1.1+deb13u1) trixie-security; urgency=medium * Non-maintainer upload by the Security Team. diff -Nru nghttp2-1.64.0/debian/patches/CVE-2026-58055.patch nghttp2-1.64.0/debian/patches/CVE-2026-58055.patch --- nghttp2-1.64.0/debian/patches/CVE-2026-58055.patch 1970-01-01 00:00:00.000000000 +0000 +++ nghttp2-1.64.0/debian/patches/CVE-2026-58055.patch 2026-09-03 21:11:20.000000000 +0000 @@ -0,0 +1,287 @@ +From ab28105c4a0197da24f8bfc414bc116055249e1e Mon Sep 17 00:00:00 2001 +From: Tatsuhiro Tsujikawa +Date: Fri, 22 May 2026 21:26:44 +0900 +Subject: [PATCH] nghttpx: Tighten up CONNECT and HTTP Upgrade handling + +--- nghttp2-1.64.0.orig/src/shrpx_downstream.cc ++++ nghttp2-1.64.0/src/shrpx_downstream.cc +@@ -1146,7 +1146,8 @@ bool Downstream::can_detach_downstream_c + // state, especially for HTTP/1.1 + return dconn_ && response_state_ == DownstreamState::MSG_COMPLETE && + request_state_ == DownstreamState::MSG_COMPLETE && !upgraded_ && +- !resp_.connection_close && request_buf_.rleft() == 0; ++ !resp_.connection_close && blocked_request_buf_.rleft() == 0 && ++ request_buf_.rleft() == 0; + } + + DefaultMemchunks Downstream::pop_response_buf() { +--- nghttp2-1.64.0.orig/src/shrpx_downstream.h ++++ nghttp2-1.64.0/src/shrpx_downstream.h +@@ -231,6 +231,10 @@ struct Request { + // orig_authority and orig_path have the authority and path which + // are used for the first backend selection. + bool forwarded_once; ++ // true if HTTP/1 request message has been completed. This field is ++ // added because Downstream::get_request_state() might be altered ++ // from DownstreamState::MSG_COMPLETE. ++ bool http1_msg_complete; + }; + + struct Response { +--- nghttp2-1.64.0.orig/src/shrpx_http2_upstream.cc ++++ nghttp2-1.64.0/src/shrpx_http2_upstream.cc +@@ -359,6 +359,14 @@ int Http2Upstream::on_request_headers(Do + return 0; + } + ++ if (method_token == HTTP_CONNECT && content_length) { ++ if (LOG_ENABLED(INFO)) { ++ ULOG(INFO, this) << "content-length are not allowed in CONNECT request"; ++ } ++ ++ return error_reply(downstream, 400); ++ } ++ + auto faddr = handler_->get_upstream_addr(); + + // For HTTP/2 proxy, we require :authority. +--- nghttp2-1.64.0.orig/src/shrpx_http3_upstream.cc ++++ nghttp2-1.64.0/src/shrpx_http3_upstream.cc +@@ -2282,6 +2282,14 @@ int Http3Upstream::http_end_request_head + return 0; + } + ++ if (method_token == HTTP_CONNECT && content_length) { ++ if (LOG_ENABLED(INFO)) { ++ ULOG(INFO, this) << "content-length are not allowed in CONNECT request"; ++ } ++ ++ return error_reply(downstream, 400); ++ } ++ + auto faddr = handler_->get_upstream_addr(); + + auto config = get_config(); +--- nghttp2-1.64.0.orig/src/shrpx_http_downstream_connection.cc ++++ nghttp2-1.64.0/src/shrpx_http_downstream_connection.cc +@@ -735,6 +735,34 @@ int HttpDownstreamConnection::push_reque + return 0; + } + ++bool HttpDownstreamConnection::should_block_request_body() const { ++ const auto &req = downstream_->request(); ++ ++ return !downstream_->get_request_header_sent() || ++ (req.upgrade_request && !downstream_->get_upgraded()); ++} ++ ++bool HttpDownstreamConnection::should_unblock_request_body_before_response() ++ const { ++ const auto &req = downstream_->request(); ++ ++ return !req.upgrade_request; ++} ++ ++void HttpDownstreamConnection::process_blocked_request_buf_on_response() { ++ if (blocked_request_buf_processed_) { ++ return; ++ } ++ ++ process_blocked_request_buf(); ++ ++ auto buf = downstream_->get_blocked_request_buf(); ++ buf->reset(); ++ blocked_request_buf_processed_ = true; ++ ++ signal_write(); ++} ++ + int HttpDownstreamConnection::process_blocked_request_buf() { + auto src = downstream_->get_blocked_request_buf(); + +@@ -764,7 +792,7 @@ int HttpDownstreamConnection::process_bl + + int HttpDownstreamConnection::push_upload_data_chunk(const uint8_t *data, + size_t datalen) { +- if (!downstream_->get_request_header_sent()) { ++ if (should_block_request_body()) { + auto output = downstream_->get_blocked_request_buf(); + auto &req = downstream_->request(); + output->append(data, datalen); +@@ -796,7 +824,7 @@ int HttpDownstreamConnection::push_uploa + } + + int HttpDownstreamConnection::end_upload_data() { +- if (!downstream_->get_request_header_sent()) { ++ if (should_block_request_body()) { + downstream_->set_blocked_request_data_eof(true); + if (request_header_written_) { + signal_write(); +@@ -997,6 +1025,11 @@ int htp_hdrs_completecb(llhttp_t *htp) { + // upgrade succeeded, 101 response is treated as final in nghttpx. + downstream->check_upgrade_fulfilled_http1(); + ++ if (req.method == HTTP_CONNECT && resp.http_status / 100 == 2 && ++ !downstream->get_upgraded()) { ++ resp.http_status = 502; ++ } ++ + if (downstream->get_non_final_response()) { + // Reset content-length because we reuse same Downstream for the + // next response. +@@ -1018,7 +1051,7 @@ int htp_hdrs_completecb(llhttp_t *htp) { + downstream->set_response_state(DownstreamState::HEADER_COMPLETE); + downstream->inspect_http1_response(); + +- if (htp->flags & F_CHUNKED) { ++ if (!downstream->get_upgraded() && (htp->flags & F_CHUNKED)) { + downstream->set_chunked_response(true); + } + +@@ -1033,13 +1066,22 @@ int htp_hdrs_completecb(llhttp_t *htp) { + resp.connection_close = true; + // transfer-encoding not applied to upgraded connection + downstream->set_chunked_response(false); +- } else if (http2::legacy_http1(req.http_major, req.http_minor)) { +- if (resp.fs.content_length == -1) { ++ ++ static_cast(dconn) ++ ->process_blocked_request_buf_on_response(); ++ } else { ++ if (req.upgrade_request) { + resp.connection_close = true; + } +- downstream->set_chunked_response(false); +- } else if (!downstream->expect_response_body()) { +- downstream->set_chunked_response(false); ++ ++ if (http2::legacy_http1(req.http_major, req.http_minor)) { ++ if (resp.fs.content_length == -1) { ++ resp.connection_close = true; ++ } ++ downstream->set_chunked_response(false); ++ } else if (!downstream->expect_response_body()) { ++ downstream->set_chunked_response(false); ++ } + } + + if (loggingconf.access.write_early && downstream->accesslog_ready()) { +@@ -1213,7 +1255,10 @@ int htp_msg_completecb(llhttp_t *htp) { + int HttpDownstreamConnection::write_first() { + int rv; + +- process_blocked_request_buf(); ++ auto should_unblock_req_body = should_unblock_request_body_before_response(); ++ if (should_unblock_req_body) { ++ process_blocked_request_buf(); ++ } + + if (conn_.tls.ssl) { + rv = write_tls(); +@@ -1234,8 +1279,11 @@ int HttpDownstreamConnection::write_firs + first_write_done_ = true; + downstream_->set_request_header_sent(true); + +- auto buf = downstream_->get_blocked_request_buf(); +- buf->reset(); ++ if (should_unblock_req_body) { ++ auto buf = downstream_->get_blocked_request_buf(); ++ buf->reset(); ++ blocked_request_buf_processed_ = true; ++ } + + // upstream->resume_read() might be called in + // write_tls()/write_clear(), but before blocked_request_buf_ is +--- nghttp2-1.64.0.orig/src/shrpx_http_downstream_connection.h ++++ nghttp2-1.64.0/src/shrpx_http_downstream_connection.h +@@ -91,6 +91,9 @@ public: + int noop(); + + int process_blocked_request_buf(); ++ void process_blocked_request_buf_on_response(); ++ bool should_unblock_request_body_before_response() const; ++ bool should_block_request_body() const; + + private: + Connection conn_; +@@ -117,6 +120,8 @@ private: + bool reusable_; + // true if request header is written to request buffer. + bool request_header_written_; ++ // true if blocked request buffer has been processed. ++ bool blocked_request_buf_processed_; + }; + + } // namespace shrpx +--- nghttp2-1.64.0.orig/src/shrpx_https_upstream.cc ++++ nghttp2-1.64.0/src/shrpx_https_upstream.cc +@@ -416,6 +416,17 @@ int htp_hdrs_completecb(llhttp_t *htp) { + + downstream->inspect_http1_request(); + ++ if ((req.upgrade_request || llhttp_get_upgrade(htp)) && ++ (req.fs.header(http2::HD_TRANSFER_ENCODING) || ++ req.fs.header(http2::HD_CONTENT_LENGTH))) { ++ if (LOG_ENABLED(INFO)) { ++ ULOG(INFO, upstream) << "transfer-encoding and content-length are not " ++ "allowed in CONNECT or upgrade request"; ++ } ++ ++ return -1; ++ } ++ + if (htp->flags & F_CHUNKED) { + downstream->set_chunked_request(true); + } +@@ -559,6 +570,16 @@ int htp_bodycb(llhttp_t *htp, const char + int rv; + auto upstream = static_cast(htp->data); + auto downstream = upstream->get_downstream(); ++ const auto &req = downstream->request(); ++ ++ if (req.upgrade_request || llhttp_get_upgrade(htp)) { ++ if (LOG_ENABLED(INFO)) { ++ ULOG(INFO, upstream) << "Request body for Upgrade request is not allowed"; ++ } ++ ++ return HPE_USER; ++ } ++ + rv = downstream->push_upload_data_chunk( + reinterpret_cast(data), len); + if (rv != 0) { +@@ -592,6 +613,7 @@ int htp_msg_completecb(llhttp_t *htp) { + } + + downstream->set_request_state(DownstreamState::MSG_COMPLETE); ++ req.http1_msg_complete = true; + rv = downstream->end_upload_data(); + if (rv != 0) { + if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) { +@@ -632,7 +654,8 @@ int HttpsUpstream::on_read() { + + // downstream can be nullptr here, because it is initialized in the + // callback chain called by llhttp_execute() +- if (downstream && downstream->get_upgraded()) { ++ if (downstream && downstream->request().http1_msg_complete && ++ downstream->get_upgraded()) { + auto rv = downstream->push_upload_data_chunk(rb->pos(), rb->rleft()); + + if (rv != 0) { +@@ -706,9 +729,13 @@ int HttpsUpstream::on_read() { + + if (htperr != HPE_OK) { + if (LOG_ENABLED(INFO)) { +- ULOG(INFO, this) << "HTTP parse failure: " +- << "(" << llhttp_errno_name(htperr) << ") " +- << llhttp_get_error_reason(&htp_); ++ if (htperr == HPE_USER) { ++ ULOG(INFO, this) << "HTTP callback error"; ++ } else { ++ ULOG(INFO, this) << "HTTP parse failure: " ++ << "(" << llhttp_errno_name(htperr) << ") " ++ << llhttp_get_error_reason(&htp_); ++ } + } + + if (downstream && diff -Nru nghttp2-1.64.0/debian/patches/series nghttp2-1.64.0/debian/patches/series --- nghttp2-1.64.0/debian/patches/series 2026-04-15 15:04:15.000000000 +0000 +++ nghttp2-1.64.0/debian/patches/series 2026-09-03 21:11:08.000000000 +0000 @@ -3,3 +3,4 @@ lp-2104171-avoid-rubydomain-namespace.patch CVE-2026-27135.patch CVE-2026-27135-test.patch +CVE-2026-58055.patch