Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package nghttp2 for openSUSE:Factory checked 
in at 2026-06-30 15:11:30
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/nghttp2 (Old)
 and      /work/SRC/openSUSE:Factory/.nghttp2.new.11887 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "nghttp2"

Tue Jun 30 15:11:30 2026 rev:91 rq:1362476 version:1.69.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/nghttp2/nghttp2.changes  2026-04-30 
20:26:18.808790294 +0200
+++ /work/SRC/openSUSE:Factory/.nghttp2.new.11887/nghttp2.changes       
2026-06-30 15:11:55.984994303 +0200
@@ -1,0 +2,8 @@
+Mon Jun 29 09:22:53 UTC 2026 - Valentin Lefebvre <[email protected]>
+
+- stricter validation for HTTP CONNECT and Upgrade requests across HTTP/1,
+  HTTP/2, and HTTP/3 upstreams, specifically rejecting requests that
+  incorrectly include Content-Length or Transfer-Encoding headers 
+  * Add 0001-nghttpx-Tighten-up-CONNECT-and-HTTP-Upgrade-handling.patch
+    CVE-2026-58055, bsc#1269489
+-------------------------------------------------------------------

New:
----
  0001-nghttpx-Tighten-up-CONNECT-and-HTTP-Upgrade-handling.patch

----------(New B)----------
  New:  incorrectly include Content-Length or Transfer-Encoding headers 
  * Add 0001-nghttpx-Tighten-up-CONNECT-and-HTTP-Upgrade-handling.patch
    CVE-2026-58055, bsc#1269489
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ nghttp2.spec ++++++
--- /var/tmp/diff_new_pack.bVVUGf/_old  2026-06-30 15:11:56.761020587 +0200
+++ /var/tmp/diff_new_pack.bVVUGf/_new  2026-06-30 15:11:56.765020723 +0200
@@ -34,6 +34,8 @@
 Source1:        
https://github.com/nghttp2/nghttp2/releases/download/v%{version}/nghttp2-%{version}.tar.xz.asc
 Source2:        nghttp2.keyring
 Source3:        baselibs.conf
+# PATCH-FIX-UPSTREAM: CVE-2026-58055
+Patch:          0001-nghttpx-Tighten-up-CONNECT-and-HTTP-Upgrade-handling.patch
 BuildRequires:  libboost_thread-devel
 BuildRequires:  pkgconfig
 BuildRequires:  pkgconfig(cunit)

++++++ 0001-nghttpx-Tighten-up-CONNECT-and-HTTP-Upgrade-handling.patch ++++++
>From ab28105c4a0197da24f8bfc414bc116055249e1e Mon Sep 17 00:00:00 2001
From: Tatsuhiro Tsujikawa <[email protected]>
Date: Fri, 22 May 2026 21:26:44 +0900
Subject: [PATCH] nghttpx: Tighten up CONNECT and HTTP Upgrade handling


[vlefebvre: adapt changes]
---
 src/shrpx_downstream.cc                 |  3 +-
 src/shrpx_downstream.h                  |  4 ++
 src/shrpx_http2_upstream.cc             |  8 +++
 src/shrpx_http3_upstream.cc             |  8 +++
 src/shrpx_http_downstream_connection.cc | 70 +++++++++++++++++++++----
 src/shrpx_http_downstream_connection.h  |  5 ++
 src/shrpx_https_upstream.cc             | 35 +++++++++++--
 7 files changed, 117 insertions(+), 16 deletions(-)

Index: nghttp2-1.69.0/src/shrpx_downstream.cc
===================================================================
--- nghttp2-1.69.0.orig/src/shrpx_downstream.cc
+++ nghttp2-1.69.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() {
Index: nghttp2-1.69.0/src/shrpx_downstream.h
===================================================================
--- nghttp2-1.69.0.orig/src/shrpx_downstream.h
+++ nghttp2-1.69.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 {
Index: nghttp2-1.69.0/src/shrpx_http2_upstream.cc
===================================================================
--- nghttp2-1.69.0.orig/src/shrpx_http2_upstream.cc
+++ nghttp2-1.69.0/src/shrpx_http2_upstream.cc
@@ -328,6 +328,14 @@ int Http2Upstream::on_request_headers(Do
     return 0;
   }
 
+  if (method_token == HTTP_CONNECT && content_length) {
+    if (log_enabled(INFO)) {
+      Log{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.
Index: nghttp2-1.69.0/src/shrpx_http3_upstream.cc
===================================================================
--- nghttp2-1.69.0.orig/src/shrpx_http3_upstream.cc
+++ nghttp2-1.69.0/src/shrpx_http3_upstream.cc
@@ -2224,6 +2224,14 @@ int Http3Upstream::http_end_request_head
     return 0;
   }
 
+  if (method_token == HTTP_CONNECT && content_length) {
+    if (log_enabled(INFO)) {
+      Log{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();
Index: nghttp2-1.69.0/src/shrpx_http_downstream_connection.cc
===================================================================
--- nghttp2-1.69.0.orig/src/shrpx_http_downstream_connection.cc
+++ nghttp2-1.69.0/src/shrpx_http_downstream_connection.cc
@@ -712,6 +712,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();
 
@@ -741,7 +769,7 @@ int HttpDownstreamConnection::process_bl
 
 int HttpDownstreamConnection::push_upload_data_chunk(
   std::span<const uint8_t> data) {
-  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);
@@ -773,7 +801,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();
@@ -974,6 +1002,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.
@@ -995,7 +1028,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);
   }
 
@@ -1010,13 +1043,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<HttpDownstreamConnection *>(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()) {
@@ -1194,7 +1236,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();
@@ -1215,8 +1260,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
Index: nghttp2-1.69.0/src/shrpx_http_downstream_connection.h
===================================================================
--- nghttp2-1.69.0.orig/src/shrpx_http_downstream_connection.h
+++ nghttp2-1.69.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
Index: nghttp2-1.69.0/src/shrpx_https_upstream.cc
===================================================================
--- nghttp2-1.69.0.orig/src/shrpx_https_upstream.cc
+++ nghttp2-1.69.0/src/shrpx_https_upstream.cc
@@ -402,6 +402,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)) {
+      Log{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);
   }
@@ -554,6 +565,16 @@ int htp_bodycb(llhttp_t *htp, const char
   int rv;
   auto upstream = static_cast<HttpsUpstream *>(htp->data);
   auto downstream = upstream->get_downstream();
+  const auto &req = downstream->request();
+
+  if (req.upgrade_request || llhttp_get_upgrade(htp)) {
+    if (log_enabled(INFO)) {
+      Log{INFO, upstream} << "Request body for Upgrade request is not allowed";
+    }
+
+    return HPE_USER;
+  }
+
   rv = downstream->push_upload_data_chunk(as_uint8_span(std::span{data, len}));
   if (rv != 0) {
     // Ignore error if response has been completed.  We will end up in
@@ -586,6 +607,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) {
@@ -626,7 +648,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->peek());
 
     if (rv != 0) {
@@ -699,9 +722,13 @@ int HttpsUpstream::on_read() {
 
   if (htperr != HPE_OK) {
     if (log_enabled(INFO)) {
-      Log{INFO, this} << "HTTP parse failure: "
-                      << "(" << llhttp_errno_name(htperr) << ") "
-                      << llhttp_get_error_reason(&htp_);
+      if (htperr == HPE_USER) {
+        Log{INFO, this} << "HTTP callback error";
+      } else {
+        Log{INFO, this} << "HTTP parse failure: "
+                        << "(" << llhttp_errno_name(htperr) << ") "
+                        << llhttp_get_error_reason(&htp_);
+      }
     }
 
     if (downstream &&

Reply via email to