Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package capnproto for openSUSE:Factory 
checked in at 2026-07-10 17:40:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/capnproto (Old)
 and      /work/SRC/openSUSE:Factory/.capnproto.new.1991 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "capnproto"

Fri Jul 10 17:40:54 2026 rev:21 rq:1364810 version:1.5.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/capnproto/capnproto.changes      2026-04-21 
12:47:07.928177078 +0200
+++ /work/SRC/openSUSE:Factory/.capnproto.new.1991/capnproto.changes    
2026-07-10 17:43:35.913901584 +0200
@@ -1,0 +2,32 @@
+Fri Jul 10 04:57:04 UTC 2026 - Luigi Baldoni <[email protected]>
+
+  * kj: tolerate ERROR_INVALID_FUNCTION from
+    GetFileInformationByHandleEx
+  * Fix bare includes in ez-rpc.h
+  * Revert rpc.h include to relative form in ez-rpc.h
+  * Add repo_name = ssl for boringssl Bzlmod compatibility
+  * Replace c++/LICENSE.txt symlink with real file
+  * Support Bazel 9 in V1
+  * Address compiler errors when building against OpenSSL 4.0
+  * Maintain compatibility with older OpenSSL versions
+  * Scope testing to project
+  * KJ HTTP: validate request URL and status text before
+    serializing
+  * KJ HTTP: reject whitespace between header name and colon
+  * KJ HTTP: reject obsolete line folding
+  * Fix infinite recursion in KJ_CONTEXT when evaluating
+    parameters throws
+  * fix offset overflow in schema loader struct validation
+  * fix off-by-one write to membersByDiscriminant in schema
+    validator
+  * Limit nesting depth when lexing textual capnp schemas
+  * Clamp rpc Exception type enum.
+  * fix segment size overflow in message readers
+  * Document security issues fixed in Cap'n Proto v1.5.
+  * Fix KJ_CONTEXT throwing test with -fno-exceptions.
+  * Fix new warning about whitespace when defining a literal
+    suffix operator.
+  * Disable new complier warning on mac since it is blocking the
+    tests.
+
+-------------------------------------------------------------------

Old:
----
  capnproto-c++-1.4.0.tar.gz

New:
----
  capnproto-c++-1.5.0.tar.gz

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

Other differences:
------------------
++++++ capnproto.spec ++++++
--- /var/tmp/diff_new_pack.xesECO/_old  2026-07-10 17:43:38.137977770 +0200
+++ /var/tmp/diff_new_pack.xesECO/_new  2026-07-10 17:43:38.137977770 +0200
@@ -22,9 +22,9 @@
 %bcond_with clang
 %endif
 
-%define _libver 1_4_0
+%define _libver 1_5_0
 Name:           capnproto
-Version:        1.4.0
+Version:        1.5.0
 Release:        0
 Summary:        A Data Serialization Format
 License:        MIT

++++++ capnproto-c++-1.4.0.tar.gz -> capnproto-c++-1.5.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/CMakeLists.txt 
new/capnproto-c++-1.5.0/CMakeLists.txt
--- old/capnproto-c++-1.4.0/CMakeLists.txt      2026-03-12 14:59:55.000000000 
+0100
+++ new/capnproto-c++-1.5.0/CMakeLists.txt      2026-07-10 00:38:56.000000000 
+0200
@@ -2,11 +2,15 @@
 include_guard(GLOBAL)
 
 project("Cap'n Proto" CXX)
-set(VERSION 1.4.0)
+set(VERSION 1.5.0)
 
 list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
 
-include(CTest)
+# PROJECT_IS_TOP_LEVEL was added in CMake 3.21
+if (NOT DEFINED PROJECT_IS_TOP_LEVEL OR PROJECT_IS_TOP_LEVEL)
+  include(CTest)
+endif()
+
 include(CheckIncludeFileCXX)
 include(GNUInstallDirs)
 if(MSVC)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/configure 
new/capnproto-c++-1.5.0/configure
--- old/capnproto-c++-1.4.0/configure   2026-03-12 14:59:57.000000000 +0100
+++ new/capnproto-c++-1.5.0/configure   2026-07-10 00:38:58.000000000 +0200
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.72 for Capn Proto 1.4.0.
+# Generated by GNU Autoconf 2.72 for Capn Proto 1.5.0.
 #
 # Report bugs to <[email protected]>.
 #
@@ -614,8 +614,8 @@
 # Identity of this package.
 PACKAGE_NAME='Capn Proto'
 PACKAGE_TARNAME='capnproto-c++'
-PACKAGE_VERSION='1.4.0'
-PACKAGE_STRING='Capn Proto 1.4.0'
+PACKAGE_VERSION='1.5.0'
+PACKAGE_STRING='Capn Proto 1.5.0'
 PACKAGE_BUGREPORT='[email protected]'
 PACKAGE_URL=''
 
@@ -1391,7 +1391,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-'configure' configures Capn Proto 1.4.0 to adapt to many kinds of systems.
+'configure' configures Capn Proto 1.5.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1462,7 +1462,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of Capn Proto 1.4.0:";;
+     short | recursive ) echo "Configuration of Capn Proto 1.5.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1593,7 +1593,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-Capn Proto configure 1.4.0
+Capn Proto configure 1.5.0
 generated by GNU Autoconf 2.72
 
 Copyright (C) 2023 Free Software Foundation, Inc.
@@ -2218,7 +2218,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by Capn Proto $as_me 1.4.0, which was
+It was created by Capn Proto $as_me 1.5.0, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -3925,7 +3925,7 @@
 
 # Define the identity of the package.
  PACKAGE='capnproto-c++'
- VERSION='1.4.0'
+ VERSION='1.5.0'
 
 
 printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -21136,7 +21136,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by Capn Proto $as_me 1.4.0, which was
+This file was extended by Capn Proto $as_me 1.5.0, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -21204,7 +21204,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-Capn Proto config.status 1.4.0
+Capn Proto config.status 1.5.0
 configured by $0, generated by GNU Autoconf 2.72,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/configure.ac 
new/capnproto-c++-1.5.0/configure.ac
--- old/capnproto-c++-1.4.0/configure.ac        2026-03-12 14:59:55.000000000 
+0100
+++ new/capnproto-c++-1.5.0/configure.ac        2026-07-10 00:38:56.000000000 
+0200
@@ -1,6 +1,6 @@
 ## Process this file with autoconf to produce configure.
 
-AC_INIT([Capn Proto],[1.4.0],[[email protected]],[capnproto-c++])
+AC_INIT([Capn Proto],[1.5.0],[[email protected]],[capnproto-c++])
 
 AC_CONFIG_SRCDIR([src/capnp/layout.c++])
 AC_CONFIG_AUX_DIR([build-aux])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/c++.capnp.h 
new/capnproto-c++-1.5.0/src/capnp/c++.capnp.h
--- old/capnproto-c++-1.4.0/src/capnp/c++.capnp.h       2026-03-12 
14:59:55.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/c++.capnp.h       2026-07-10 
00:38:56.000000000 +0200
@@ -8,7 +8,7 @@
 
 #ifndef CAPNP_VERSION
 #error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h 
missing?"
-#elif CAPNP_VERSION != 1004000
+#elif CAPNP_VERSION != 1005000
 #error "Version mismatch between generated code and library headers.  You must 
use the same version of the Cap'n Proto compiler and library."
 #endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/common.h 
new/capnproto-c++-1.5.0/src/capnp/common.h
--- old/capnproto-c++-1.4.0/src/capnp/common.h  2026-03-12 14:59:55.000000000 
+0100
+++ new/capnproto-c++-1.5.0/src/capnp/common.h  2026-07-10 00:38:56.000000000 
+0200
@@ -47,7 +47,7 @@
 namespace capnp {
 
 #define CAPNP_VERSION_MAJOR 1
-#define CAPNP_VERSION_MINOR 4
+#define CAPNP_VERSION_MINOR 5
 #define CAPNP_VERSION_MICRO 0
 
 #define CAPNP_VERSION \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/compat/json.capnp.h 
new/capnproto-c++-1.5.0/src/capnp/compat/json.capnp.h
--- old/capnproto-c++-1.4.0/src/capnp/compat/json.capnp.h       2026-03-12 
14:59:55.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/compat/json.capnp.h       2026-07-10 
00:38:56.000000000 +0200
@@ -11,7 +11,7 @@
 
 #ifndef CAPNP_VERSION
 #error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h 
missing?"
-#elif CAPNP_VERSION != 1004000
+#elif CAPNP_VERSION != 1005000
 #error "Version mismatch between generated code and library headers.  You must 
use the same version of the Cap'n Proto compiler and library."
 #endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/capnproto-c++-1.4.0/src/capnp/compiler/grammar.capnp.h 
new/capnproto-c++-1.5.0/src/capnp/compiler/grammar.capnp.h
--- old/capnproto-c++-1.4.0/src/capnp/compiler/grammar.capnp.h  2026-03-12 
14:59:55.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/compiler/grammar.capnp.h  2026-07-10 
00:38:56.000000000 +0200
@@ -8,7 +8,7 @@
 
 #ifndef CAPNP_VERSION
 #error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h 
missing?"
-#elif CAPNP_VERSION != 1004000
+#elif CAPNP_VERSION != 1005000
 #error "Version mismatch between generated code and library headers.  You must 
use the same version of the Cap'n Proto compiler and library."
 #endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/capnproto-c++-1.4.0/src/capnp/compiler/lexer-test.c++ 
new/capnproto-c++-1.5.0/src/capnp/compiler/lexer-test.c++
--- old/capnproto-c++-1.4.0/src/capnp/compiler/lexer-test.c++   2023-11-21 
17:03:29.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/compiler/lexer-test.c++   2026-07-10 
00:33:53.000000000 +0200
@@ -368,6 +368,57 @@
       doLex<LexedTokens>("\xef\xbb\xbf""foo bar\xef\xbb\xbf""baz").cStr());
 }
 
+class TestCountingErrorReporter: public ErrorReporter {
+public:
+  uint errorCount = 0;
+  void addError(uint32_t startByte, uint32_t endByte, kj::StringPtr message) 
override {
+    ++errorCount;
+  }
+  bool hadErrors() override {
+    return errorCount > 0;
+  }
+};
+
+kj::String nested(char open, char close, uint count) {
+  // Produces a string of `count` `open` chars followed by `count` `close` 
chars.
+  auto result = kj::heapString(count * 2);
+  for (uint i = 0; i < count; i++) {
+    result[i] = open;
+    result[count + i] = close;
+  }
+  return result;
+}
+
+TEST(Lexer, DeeplyNestedInputDoesNotOverflowStack) {
+  // Regression test for a stack-overflow vulnerability: the lexer is a 
recursive-descent parser,
+  // so deeply-nested brackets/braces could overflow the stack and crash the 
process. The lexer now
+  // enforces a maximum nesting depth, rejecting over-nested input rather than 
crashing.
+
+  auto tryLexTokens = [](kj::StringPtr text) {
+    MallocMessageBuilder message;
+    auto file = message.initRoot<LexedTokens>();
+    TestCountingErrorReporter errorReporter;
+    return lex(text, file, errorReporter);
+  };
+  auto tryLexStatements = [](kj::StringPtr text) {
+    MallocMessageBuilder message;
+    auto file = message.initRoot<LexedStatements>();
+    TestCountingErrorReporter errorReporter;
+    return lex(text, file, errorReporter);
+  };
+
+  // A reasonable amount of nesting is accepted.
+  EXPECT_TRUE(tryLexTokens(nested('(', ')', 30)));
+  EXPECT_TRUE(tryLexTokens(nested('[', ']', 30)));
+  EXPECT_TRUE(tryLexStatements(nested('{', '}', 30)));
+
+  // Extremely deep nesting is rejected (rather than crashing with a stack 
overflow). We use a
+  // large count that would definitely overflow the stack absent the depth 
limit.
+  EXPECT_FALSE(tryLexTokens(nested('(', ')', 100000)));       // parenthesized 
lists
+  EXPECT_FALSE(tryLexTokens(nested('[', ']', 100000)));       // bracketed 
lists
+  EXPECT_FALSE(tryLexStatements(nested('{', '}', 100000)));   // curly-brace 
blocks
+}
+
 }  // namespace
 }  // namespace compiler
 }  // namespace capnp
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/compiler/lexer.c++ 
new/capnproto-c++-1.5.0/src/capnp/compiler/lexer.c++
--- old/capnproto-c++-1.4.0/src/capnp/compiler/lexer.c++        2025-12-16 
23:16:27.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/compiler/lexer.c++        2026-07-10 
00:33:53.000000000 +0200
@@ -74,6 +74,49 @@
 
 namespace {
 
+constexpr uint MAX_NESTING_DEPTH = 64;
+// Maximum allowed nesting depth of parentheses/brackets/braces in a schema 
file. The lexer is a
+// recursive-descent parser, so each level of nesting consumes stack space; 
without a limit, a
+// maliciously-crafted input consisting of deeply-nested brackets could 
overflow the stack and
+// crash the process. This limit is far larger than any legitimate schema 
requires.
+//
+// Note that this single limit protects both the lexer and the later parsing 
stages: the lexer
+// builds nested token/statement trees whose depth is bounded here, and the 
parser (parser.c++)
+// merely recurses over those already-bounded trees.
+
+template <typename SubParser>
+class NestingGuard {
+  // Parser combinator which wraps another parser, incrementing a shared depth 
counter for the
+  // duration of the sub-parser and failing (without recursing) if the depth 
would exceed
+  // MAX_NESTING_DEPTH. Placed at each point where the grammar can recurse, 
this bounds the total
+  // recursion depth and thus the stack usage.
+public:
+  explicit constexpr NestingGuard(uint& depth, SubParser&& subParser)
+      : depth(depth), subParser(kj::mv(subParser)) {}
+
+  template <typename Input>
+  auto operator()(Input& input) const
+      -> decltype(kj::instance<const SubParser&>()(input)) {
+    if (depth >= MAX_NESTING_DEPTH) {
+      // Too deeply nested; refuse to recurse further. This causes a parse 
failure which will be
+      // reported as a generic parse error at this location.
+      return nullptr;
+    }
+    ++depth;
+    KJ_DEFER(--depth);
+    return subParser(input);
+  }
+
+private:
+  uint& depth;
+  SubParser subParser;
+};
+
+template <typename SubParser>
+constexpr NestingGuard<SubParser> nestingGuard(uint& depth, SubParser&& 
subParser) {
+  return NestingGuard<SubParser>(depth, kj::fwd<SubParser>(subParser));
+}
+
 typedef p::Span<uint32_t> Location;
 
 Token::Builder initTok(Orphan<Token>& t, const Location& loc) {
@@ -173,7 +216,7 @@
         }
       }));
 
-  auto& token = arena.copy(p::oneOf(
+  auto& rawToken = arena.copy(p::oneOf(
       p::transformWithLocation(p::identifier,
           [this](Location loc, kj::String name) -> Orphan<Token> {
             auto t = orphanage.newOrphan<Token>();
@@ -250,6 +293,11 @@
                 "Non-UTF-8 input detected. Cap'n Proto schema files must be 
UTF-8 text.");
             return nullptr;
           }), [](kj::Maybe<Orphan<Token>> param) { return param; })));
+
+  // Wrap `token` in a nesting guard so that recursion through 
parenthesized/bracketed lists (which
+  // go token -> commaDelimitedList -> tokenSequence -> token) is 
depth-limited.
+  auto& token = arena.copy(nestingGuard(nestingDepth, 
p::ref<ParserInput>(rawToken)));
+
   parsers.tokenSequence = arena.copy(p::sequence(
       commentsAndWhitespace, p::many(p::sequence(token, 
commentsAndWhitespace))));
 
@@ -288,7 +336,7 @@
           })
       ));
 
-  auto& statement = 
arena.copy(p::transformWithLocation(p::sequence(tokenSequence, statementEnd),
+  auto& rawStatement = 
arena.copy(p::transformWithLocation(p::sequence(tokenSequence, statementEnd),
       [](Location loc, kj::Array<Orphan<Token>>&& tokens, Orphan<Statement>&& 
statement) {
         auto builder = statement.get();
         auto tokensBuilder = builder.initTokens(tokens.size());
@@ -300,6 +348,11 @@
         return kj::mv(statement);
       }));
 
+  // Wrap `statement` in a nesting guard so that recursion through curly-brace 
blocks (which go
+  // statement -> statementEnd -> statementSequence -> statement) is 
depth-limited. This shares the
+  // same depth counter as the token guard above, so the limit applies to the 
total nesting depth.
+  auto& statement = arena.copy(nestingGuard(nestingDepth, 
p::ref<ParserInput>(rawStatement)));
+
   parsers.statementSequence = arena.copy(sequence(
       commentsAndWhitespace, many(sequence(statement, 
commentsAndWhitespace))));
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/compiler/lexer.capnp.h 
new/capnproto-c++-1.5.0/src/capnp/compiler/lexer.capnp.h
--- old/capnproto-c++-1.4.0/src/capnp/compiler/lexer.capnp.h    2026-03-12 
14:59:55.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/compiler/lexer.capnp.h    2026-07-10 
00:38:56.000000000 +0200
@@ -8,7 +8,7 @@
 
 #ifndef CAPNP_VERSION
 #error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h 
missing?"
-#elif CAPNP_VERSION != 1004000
+#elif CAPNP_VERSION != 1005000
 #error "Version mismatch between generated code and library headers.  You must 
use the same version of the Cap'n Proto compiler and library."
 #endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/compiler/lexer.h 
new/capnproto-c++-1.5.0/src/capnp/compiler/lexer.h
--- old/capnproto-c++-1.4.0/src/capnp/compiler/lexer.h  2023-11-21 
17:03:29.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/compiler/lexer.h  2026-07-10 
00:33:53.000000000 +0200
@@ -91,6 +91,11 @@
   Orphanage orphanage;
   kj::Arena arena;
   Parsers parsers;
+
+  uint nestingDepth = 0;
+  // Tracks the current recursion depth of the recursive-descent parser, so 
that maliciously-nested
+  // input (e.g. deeply-nested parentheses, brackets, or curly-brace blocks) 
can be rejected before
+  // it overflows the stack. See NestingGuard in lexer.c++.
 };
 
 }  // namespace compiler
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/ez-rpc.h 
new/capnproto-c++-1.5.0/src/capnp/ez-rpc.h
--- old/capnproto-c++-1.4.0/src/capnp/ez-rpc.h  2025-12-16 23:16:27.000000000 
+0100
+++ new/capnproto-c++-1.5.0/src/capnp/ez-rpc.h  2026-07-10 00:33:53.000000000 
+0200
@@ -22,7 +22,7 @@
 #pragma once
 
 #include "rpc.h"
-#include "message.h"
+#include <capnp/message.h>
 
 CAPNP_BEGIN_HEADER
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/persistent.capnp.h 
new/capnproto-c++-1.5.0/src/capnp/persistent.capnp.h
--- old/capnproto-c++-1.4.0/src/capnp/persistent.capnp.h        2026-03-12 
14:59:55.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/persistent.capnp.h        2026-07-10 
00:38:56.000000000 +0200
@@ -11,7 +11,7 @@
 
 #ifndef CAPNP_VERSION
 #error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h 
missing?"
-#elif CAPNP_VERSION != 1004000
+#elif CAPNP_VERSION != 1005000
 #error "Version mismatch between generated code and library headers.  You must 
use the same version of the Cap'n Proto compiler and library."
 #endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/rpc-test.c++ 
new/capnproto-c++-1.5.0/src/capnp/rpc-test.c++
--- old/capnproto-c++-1.4.0/src/capnp/rpc-test.c++      2025-12-16 
23:16:27.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/rpc-test.c++      2026-07-10 
00:33:53.000000000 +0200
@@ -1311,6 +1311,42 @@
   EXPECT_TRUE(conn->receiveIncomingMessage().wait(context.waitScope) == 
nullptr);
 }
 
+KJ_TEST("abort with invalid exception type") {
+  // Regression test: a peer sends an abort message with an out-of-range 
Exception::type.
+  // Cap'n Proto enums are raw UInt16 on the wire, so any value 0-65535 is 
possible.
+  // The server must handle this gracefully (clamp to FAILED) rather than 
crashing
+  // due to an out-of-bounds array access in KJ_STRINGIFY(Exception::Type).
+
+  TestContext context;
+
+  MallocMessageBuilder refMessage(128);
+  auto hostId = refMessage.initRoot<test::TestSturdyRefHostId>();
+  hostId.setHost("server");
+
+  auto conn = KJ_ASSERT_NONNULL(context.clientNetwork.connect(hostId));
+
+  {
+    // Send an abort with an out-of-range exception type (0xFFFF).
+    auto msg = conn->newOutgoingMessage(128);
+    auto abort = msg->getBody().initAs<rpc::Message>().initAbort();
+    abort.setReason("malformed type test");
+    abort.setType(static_cast<rpc::Exception::Type>(0xFFFF));
+    msg->send();
+  }
+
+  // The server should handle the malformed abort without crashing. It 
disconnects and
+  // sends its own abort back (with the clamped exception type).
+  auto reply = 
KJ_ASSERT_NONNULL(conn->receiveIncomingMessage().wait(context.waitScope));
+  KJ_EXPECT(reply->getBody().getAs<rpc::Message>().which() == 
rpc::Message::ABORT);
+
+  // Verify the abort response has a valid (clamped) exception type.
+  auto responseException = reply->getBody().getAs<rpc::Message>().getAbort();
+  KJ_EXPECT(responseException.getType() == rpc::Exception::Type::FAILED);
+
+  // Connection should then close.
+  KJ_EXPECT(conn->receiveIncomingMessage().wait(context.waitScope) == nullptr);
+}
+
 KJ_TEST("handles exceptions thrown during disconnect") {
   // This is similar to the earlier "abort" test, but throws an exception on
   // connection shutdown, to exercise the RpcConnectionState error handler.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/rpc-twoparty.capnp.h 
new/capnproto-c++-1.5.0/src/capnp/rpc-twoparty.capnp.h
--- old/capnproto-c++-1.4.0/src/capnp/rpc-twoparty.capnp.h      2026-03-12 
14:59:55.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/rpc-twoparty.capnp.h      2026-07-10 
00:38:56.000000000 +0200
@@ -11,7 +11,7 @@
 
 #ifndef CAPNP_VERSION
 #error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h 
missing?"
-#elif CAPNP_VERSION != 1004000
+#elif CAPNP_VERSION != 1005000
 #error "Version mismatch between generated code and library headers.  You must 
use the same version of the Cap'n Proto compiler and library."
 #endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/rpc.c++ 
new/capnproto-c++-1.5.0/src/capnp/rpc.c++
--- old/capnproto-c++-1.4.0/src/capnp/rpc.c++   2025-12-16 23:16:27.000000000 
+0100
+++ new/capnproto-c++-1.5.0/src/capnp/rpc.c++   2026-07-10 00:33:53.000000000 
+0200
@@ -120,8 +120,18 @@
     }
   }();
 
-  kj::Exception result(static_cast<kj::Exception::Type>(exception.getType()),
-      "(remote)", 0, kj::mv(reason));
+  // Cap'n Proto enums are encoded as raw UInt16 on the wire, so a peer can 
send any value 0-65535.
+  // We must clamp to valid kj::Exception::Type values to avoid undefined 
behavior (e.g. out-of-
+  // bounds array access when stringifying the exception type).
+  kj::Exception::Type type = kj::Exception::Type::FAILED;
+  switch (exception.getType()) {
+    case rpc::Exception::Type::FAILED:        type = 
kj::Exception::Type::FAILED; break;
+    case rpc::Exception::Type::OVERLOADED:    type = 
kj::Exception::Type::OVERLOADED; break;
+    case rpc::Exception::Type::DISCONNECTED:  type = 
kj::Exception::Type::DISCONNECTED; break;
+    case rpc::Exception::Type::UNIMPLEMENTED: type = 
kj::Exception::Type::UNIMPLEMENTED; break;
+  }
+
+  kj::Exception result(type, "(remote)", 0, kj::mv(reason));
   if (exception.hasTrace()) {
     result.setRemoteTrace(kj::str(exception.getTrace()));
   }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/rpc.capnp.h 
new/capnproto-c++-1.5.0/src/capnp/rpc.capnp.h
--- old/capnproto-c++-1.4.0/src/capnp/rpc.capnp.h       2026-03-12 
14:59:55.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/rpc.capnp.h       2026-07-10 
00:38:56.000000000 +0200
@@ -8,7 +8,7 @@
 
 #ifndef CAPNP_VERSION
 #error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h 
missing?"
-#elif CAPNP_VERSION != 1004000
+#elif CAPNP_VERSION != 1005000
 #error "Version mismatch between generated code and library headers.  You must 
use the same version of the Cap'n Proto compiler and library."
 #endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/schema-loader-test.c++ 
new/capnproto-c++-1.5.0/src/capnp/schema-loader-test.c++
--- old/capnproto-c++-1.4.0/src/capnp/schema-loader-test.c++    2025-12-16 
23:16:27.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/schema-loader-test.c++    2026-07-10 
00:33:53.000000000 +0200
@@ -233,6 +233,31 @@
       loadUnderAlternateTypeId<test::TestAllTypes>(loader, 
typeId<test::TestListDefaults>()));
 }
 
+TEST(SchemaLoader, OutOfBoundsFieldOffset) {
+  // A field's offset is a UInt32 taken straight from the schema node. The 
validator must reject
+  // offsets that don't fit within the struct's declared data section, because 
the layout code
+  // (StructBuilder::setDataField) trusts the offset and does no bounds check 
of its own. An offset
+  // near 2^32 used to slip through, because the bounds check evaluated 
(offset + 1) * bits in
+  // 32-bit arithmetic, which wraps around to a small value.
+  SchemaLoader loader;
+
+  MallocMessageBuilder builder;
+  builder.setRoot(Schema::from<test::TestAllTypes>().getProto());
+  auto node = builder.getRoot<schema::Node>();
+
+  bool found = false;
+  for (auto field: node.getStruct().getFields()) {
+    if (field.isSlot() && field.getSlot().getType().isUint64()) {
+      field.getSlot().setOffset(0xffffffffu);
+      found = true;
+      break;
+    }
+  }
+  ASSERT_TRUE(found);
+
+  EXPECT_NONFATAL_FAILURE(loader.load(node));
+}
+
 TEST(SchemaLoader, Enumerate) {
   SchemaLoader loader;
   loader.loadCompiledTypeAndDependencies<TestAllTypes>();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/schema-loader.c++ 
new/capnproto-c++-1.5.0/src/capnp/schema-loader.c++
--- old/capnproto-c++-1.4.0/src/capnp/schema-loader.c++ 2025-12-16 
23:16:27.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/schema-loader.c++ 2026-07-10 
00:33:53.000000000 +0200
@@ -327,8 +327,9 @@
       VALIDATE_SCHEMA(structNode.getDiscriminantCount() <= fields.size(),
                       "struct can't have more union fields than total fields");
 
-      VALIDATE_SCHEMA((structNode.getDiscriminantOffset() + 1) * 16 <= 
dataSizeInBits,
-                      "union discriminant is out-of-bounds");
+      VALIDATE_SCHEMA(
+          (static_cast<uint64_t>(structNode.getDiscriminantOffset()) + 1) * 16 
<= dataSizeInBits,
+          "union discriminant is out-of-bounds");
     }
 
     membersByDiscriminant = 
loader.arena.allocateArray<uint16_t>(fields.size());
@@ -361,7 +362,7 @@
 
         membersByDiscriminant[discriminantPos++] = index;
       } else {
-        VALIDATE_SCHEMA(nonDiscriminantPos <= fields.size(),
+        VALIDATE_SCHEMA(nonDiscriminantPos < fields.size(),
                         "discriminantCount did not match fields");
         membersByDiscriminant[nonDiscriminantPos++] = index;
       }
@@ -373,10 +374,11 @@
           uint fieldBits = 0;
           bool fieldIsPointer = false;
           validate(slot.getType(), slot.getDefaultValue(), &fieldBits, 
&fieldIsPointer);
-          VALIDATE_SCHEMA(fieldBits * (slot.getOffset() + 1) <= dataSizeInBits 
&&
-                          fieldIsPointer * (slot.getOffset() + 1) <= 
pointerCount,
+          uint64_t offset = slot.getOffset();
+          VALIDATE_SCHEMA(fieldBits * (offset + 1) <= dataSizeInBits &&
+                          fieldIsPointer * (offset + 1) <= pointerCount,
                           "field offset out-of-bounds",
-                          slot.getOffset(), dataSizeInBits, pointerCount);
+                          offset, dataSizeInBits, pointerCount);
 
           break;
         }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/schema.capnp.h 
new/capnproto-c++-1.5.0/src/capnp/schema.capnp.h
--- old/capnproto-c++-1.4.0/src/capnp/schema.capnp.h    2026-03-12 
14:59:55.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/schema.capnp.h    2026-07-10 
00:38:56.000000000 +0200
@@ -8,7 +8,7 @@
 
 #ifndef CAPNP_VERSION
 #error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h 
missing?"
-#elif CAPNP_VERSION != 1004000
+#elif CAPNP_VERSION != 1005000
 #error "Version mismatch between generated code and library headers.  You must 
use the same version of the Cap'n Proto compiler and library."
 #endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/serialize-async.c++ 
new/capnproto-c++-1.5.0/src/capnp/serialize-async.c++
--- old/capnproto-c++-1.4.0/src/capnp/serialize-async.c++       2026-03-12 
14:11:58.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/serialize-async.c++       2026-07-10 
00:33:53.000000000 +0200
@@ -140,7 +140,7 @@
 
 kj::Promise<void> AsyncMessageReader::readSegments(kj::AsyncInputStream& 
inputStream,
                                                    kj::ArrayPtr<word> 
scratchSpace) {
-  size_t totalWords = segment0Size();
+  uint64_t totalWords = segment0Size();
 
   if (segmentCount() > 1) {
     for (uint i = 0; i < segmentCount() - 1; i++) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/serialize.c++ 
new/capnproto-c++-1.5.0/src/capnp/serialize.c++
--- old/capnproto-c++-1.4.0/src/capnp/serialize.c++     2026-03-12 
14:11:58.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/serialize.c++     2026-07-10 
00:33:53.000000000 +0200
@@ -55,7 +55,7 @@
   {
     uint segmentSize = table[1].get();
 
-    KJ_REQUIRE(array.size() >= offset + segmentSize,
+    KJ_REQUIRE(array.size() - offset >= segmentSize,
                "Message ends prematurely in first segment.") {
       return;
     }
@@ -70,7 +70,7 @@
     for (uint i = 1; i < segmentCount; i++) {
       uint segmentSize = table[i + 1].get();
 
-      KJ_REQUIRE(array.size() >= offset + segmentSize, "Message ends 
prematurely.") {
+      KJ_REQUIRE(array.size() - offset >= segmentSize, "Message ends 
prematurely.") {
         moreSegments = nullptr;
         return;
       }
@@ -188,7 +188,7 @@
   uint segmentCount = firstWord[0].get() + 1;
   uint segment0Size = firstWord[1].get();
 
-  size_t totalWords = segment0Size;
+  uint64_t totalWords = segment0Size;
 
   // Reject messages with too many segments for security reasons.
   // Use firstWord[0].get() here instead of segmentCount to catch overflow. 
The actual limit
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/capnp/stream.capnp.h 
new/capnproto-c++-1.5.0/src/capnp/stream.capnp.h
--- old/capnproto-c++-1.4.0/src/capnp/stream.capnp.h    2026-03-12 
14:59:55.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/capnp/stream.capnp.h    2026-07-10 
00:38:56.000000000 +0200
@@ -8,7 +8,7 @@
 
 #ifndef CAPNP_VERSION
 #error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h 
missing?"
-#elif CAPNP_VERSION != 1004000
+#elif CAPNP_VERSION != 1005000
 #error "Version mismatch between generated code and library headers.  You must 
use the same version of the Cap'n Proto compiler and library."
 #endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/kj/compat/http-test.c++ 
new/capnproto-c++-1.5.0/src/kj/compat/http-test.c++
--- old/capnproto-c++-1.4.0/src/kj/compat/http-test.c++ 2026-03-12 
14:39:15.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/kj/compat/http-test.c++ 2026-07-10 
00:33:53.000000000 +0200
@@ -308,6 +308,104 @@
   }
 }
 
+KJ_TEST("HttpHeaders reject whitespace before colon") {
+  // RFC 9112 section 5.1 requires rejecting a header with whitespace between 
the field name and the
+  // colon. Historically KJ silently stripped it, which -- paired with a peer 
that treats the space
+  // as part of the name -- could enable HTTP desync / request smuggling.
+  auto table = HttpHeaderTable::Builder().build();
+  HttpHeaders headers(*table);
+
+  // Space before the colon.
+  {
+    auto input = kj::heapString(
+        "POST   /some/path   HTTP/1.1\r\n"
+        "Host: example.com\r\n"
+        "Content-Length : 0\r\n"
+        "\r\n");
+
+    auto protocolError = 
headers.tryParseRequest(input).get<HttpHeaders::ProtocolError>();
+
+    KJ_EXPECT(protocolError.statusCode == 400, protocolError.statusCode);
+    KJ_EXPECT(protocolError.description == "The headers sent by your client 
are not valid.",
+        protocolError.description);
+  }
+
+  // Tab before the colon.
+  {
+    auto input = kj::heapString(
+        "POST   /some/path   HTTP/1.1\r\n"
+        "Host: example.com\r\n"
+        "Content-Length\t: 0\r\n"
+        "\r\n");
+
+    auto protocolError = 
headers.tryParseRequest(input).get<HttpHeaders::ProtocolError>();
+
+    KJ_EXPECT(protocolError.statusCode == 400, protocolError.statusCode);
+  }
+
+  // Whitespace *after* the colon (i.e. before the value) is still allowed and 
stripped.
+  {
+    auto input = kj::heapString(
+        "POST   /some/path   HTTP/1.1\r\n"
+        "Host: example.com\r\n"
+        "Content-Length:    123\r\n"
+        "\r\n");
+
+    auto result = headers.tryParseRequest(input).get<HttpHeaders::Request>();
+    KJ_EXPECT(result.method == HttpMethod::POST);
+    KJ_EXPECT(KJ_ASSERT_NONNULL(headers.get(HttpHeaderId::CONTENT_LENGTH)) == 
"123");
+  }
+}
+
+KJ_TEST("HttpHeaders reject obsolete line folding") {
+  // RFC 9112 section 7.1.4 deprecates line folding and allows rejecting it 
with 400 (Bad Request).
+  // Folding has historically been a source of HTTP desync when peers disagree 
about whether a
+  // folded line is a continuation or a new header, so KJ rejects it.
+  auto table = HttpHeaderTable::Builder().build();
+
+  // Folded value with a leading space on the continuation line.
+  {
+    HttpHeaders headers(*table);
+    auto input = kj::heapString(
+        "POST   /some/path   HTTP/1.1\r\n"
+        "Host: example.com\r\n"
+        "Some-Header: a really long\r\n"
+        "   header value\r\n"
+        "\r\n");
+
+    auto protocolError = 
headers.tryParseRequest(input).get<HttpHeaders::ProtocolError>();
+    KJ_EXPECT(protocolError.statusCode == 400, protocolError.statusCode);
+  }
+
+  // Folded value with a leading tab on the continuation line.
+  {
+    HttpHeaders headers(*table);
+    auto input = kj::heapString(
+        "POST   /some/path   HTTP/1.1\r\n"
+        "Host: example.com\r\n"
+        "Some-Header: a really long\r\n"
+        "\theader value\r\n"
+        "\r\n");
+
+    auto protocolError = 
headers.tryParseRequest(input).get<HttpHeaders::ProtocolError>();
+    KJ_EXPECT(protocolError.statusCode == 400, protocolError.statusCode);
+  }
+
+  // Folding used to smuggle what looks like a separate header.
+  {
+    HttpHeaders headers(*table);
+    auto input = kj::heapString(
+        "HTTP/1.1 200 OK\r\n"
+        "Host: example.com\r\n"
+        "Some-Header: value\r\n"
+        " Smuggled-Header: value\r\n"
+        "\r\n");
+
+    auto protocolError = 
headers.tryParseResponse(input).get<HttpHeaders::ProtocolError>();
+    KJ_EXPECT(protocolError.statusCode == 502, protocolError.statusCode);
+  }
+}
+
 KJ_TEST("HttpHeaders require valid HttpHeaderTable") {
   const auto ERROR_MESSAGE =
       "HttpHeaders object was constructed from HttpHeaderTable "
@@ -373,6 +471,52 @@
   KJ_EXPECT_THROW_MESSAGE("invalid header value", headers.add("Valid-Name", 
"in\nvalid"));
 }
 
+KJ_TEST("HttpHeaders serialization validation") {
+  // The serialization functions must reject request URLs and status texts 
containing characters
+  // that would allow HTTP desync / request smuggling (e.g. when 
http-over-capnp forwards untrusted
+  // metadata to a plain-HTTP connection). See GHSL-2026-146.
+  auto table = HttpHeaderTable::Builder().build();
+  HttpHeaders headers(*table);
+
+  // Valid values serialize fine.
+  KJ_EXPECT(headers.serializeRequest(HttpMethod::GET, "/some/path?query=1") ==
+      "GET /some/path?query=1 HTTP/1.1\r\n\r\n");
+  KJ_EXPECT(headers.serializeResponse(200, "OK") ==
+      "HTTP/1.1 200 OK\r\n\r\n");
+
+  // A CRLF in the URL could inject headers or an entire second request.
+  KJ_EXPECT_THROW_MESSAGE("invalid request URL",
+      headers.serializeRequest(HttpMethod::GET, "/foo\r\nX-Injected: 1"));
+
+  // A bare LF is equally dangerous.
+  KJ_EXPECT_THROW_MESSAGE("invalid request URL",
+      headers.serializeRequest(HttpMethod::GET, "/foo\nbar"));
+
+  // A space in the request-target would introduce an extra token into the 
request line.
+  KJ_EXPECT_THROW_MESSAGE("invalid request URL",
+      headers.serializeRequest(HttpMethod::GET, "/foo bar"));
+
+  // A NUL byte terminates the C string and could truncate the request line.
+  KJ_EXPECT_THROW_MESSAGE("invalid request URL",
+      headers.serializeRequest(HttpMethod::GET, kj::StringPtr("/foo\0bar", 
8)));
+
+  // CONNECT authority is validated too.
+  KJ_EXPECT_THROW_MESSAGE("invalid request URL",
+      headers.serializeConnectRequest("example.com:443\r\nX-Injected: 1"));
+
+  // A CRLF in the status text could inject headers into the response.
+  KJ_EXPECT_THROW_MESSAGE("invalid status text",
+      headers.serializeResponse(200, "OK\r\nX-Injected: 1"));
+
+  // A bare LF is equally dangerous.
+  KJ_EXPECT_THROW_MESSAGE("invalid status text",
+      headers.serializeResponse(200, "OK\nfoo"));
+
+  // Status text may legitimately contain spaces.
+  KJ_EXPECT(headers.serializeResponse(418, "I'm a teapot") ==
+      "HTTP/1.1 418 I'm a teapot\r\n\r\n");
+}
+
 KJ_TEST("HttpHeaders Set-Cookie handling") {
   HttpHeaderTable::Builder builder;
   auto hCookie = builder.add("Cookie");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/kj/compat/http.c++ 
new/capnproto-c++-1.5.0/src/kj/compat/http.c++
--- old/capnproto-c++-1.4.0/src/kj/compat/http.c++      2026-03-12 
14:11:58.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/kj/compat/http.c++      2026-07-10 
00:33:53.000000000 +0200
@@ -499,6 +499,40 @@
       kj::encodeCEscape(value));
 }
 
+static bool isValidRequestUrl(kj::StringPtr url) {
+  // The request-target (URL) appears in the request line as `METHOD SP 
request-target SP version`.
+  // It must not contain whitespace (which would introduce extra tokens into 
the request line) nor
+  // any control characters (in particular CR or LF, which would allow 
injecting additional headers
+  // or entire requests). We reject any byte <= 0x20 (this covers space, tab, 
CR, LF, and NUL) as
+  // well as 0x7f (DEL). Bytes >= 0x80 are permitted since some callers pass 
pre-encoded or
+  // non-ASCII targets; these cannot cause desync.
+  for (char c: url) {
+    if (static_cast<byte>(c) <= 0x20 || static_cast<byte>(c) == 0x7f) {
+      return false;
+    }
+  }
+  return true;
+}
+
+static void requireValidRequestUrl(kj::StringPtr url) {
+  KJ_REQUIRE(isValidRequestUrl(url), "invalid request URL", 
kj::encodeCEscape(url));
+}
+
+static bool isValidStatusText(kj::StringPtr text) {
+  // The status text (reason-phrase) appears at the end of the response status 
line. It must not
+  // contain CR, LF, or NUL, which would allow injecting additional headers or 
corrupt the framing.
+  for (char c: text) {
+    if (c == '\0' || c == '\r' || c == '\n') {
+      return false;
+    }
+  }
+  return true;
+}
+
+static void requireValidStatusText(kj::StringPtr text) {
+  KJ_REQUIRE(isValidStatusText(text), "invalid status text", 
kj::encodeCEscape(text));
+}
+
 static const char* BUILTIN_HEADER_NAMES[] = {
   // Indexed by header ID, which includes connection headers, so we include 
those names too.
 #define HEADER_NAME(id, name) name,
@@ -824,7 +858,10 @@
   }
 }
 
-static kj::StringPtr consumeLine(char*& ptr) {
+static kj::StringPtr consumeLine(char*& ptr, bool* sawFolding = nullptr) {
+  // If `sawFolding` is non-null, it is set to true if an obsolete "line 
folding" continuation was
+  // encountered. Callers that parse header fields use this to reject the 
message (see
+  // parseHeaders()).
   char* start = skipSpace(ptr);
   char* p = start;
 
@@ -843,6 +880,7 @@
           // a space was treated as a continuation of the previous line. The 
behavior should be
           // the same as if the \r\n were replaced with spaces, so let's do 
that here to prevent
           // confusion later.
+          if (sawFolding != nullptr) *sawFolding = true;
           *end = ' ';
           p[-1] = ' ';
           break;
@@ -861,6 +899,7 @@
           // a space was treated as a continuation of the previous line. The 
behavior should be
           // the same as if the \n were replaced with spaces, so let's do that 
here to prevent
           // confusion later.
+          if (sawFolding != nullptr) *sawFolding = true;
           *end = ' ';
           break;
         }
@@ -886,7 +925,11 @@
   while (HTTP_HEADER_NAME_CHARS.contains(*p)) ++p;
   char* end = p;
 
-  p = skipSpace(p);
+  // Note: We intentionally do NOT skip whitespace between the header name and 
the colon. RFC 9112
+  // section 5.1 requires that no whitespace appear there, and that a message 
with such whitespace
+  // be rejected with 400 (Bad Request). Historically some HTTP 
implementations treated the
+  // trailing whitespace as part of the header name, which -- if a message 
passed through both such
+  // an implementation and a lenient one -- could lead to HTTP desync / 
request smuggling.
 
   if (end == start || *p != ':') return nullptr;
   ++p;
@@ -1030,7 +1073,15 @@
 bool HttpHeaders::parseHeaders(char* ptr, char* end) {
   while (*ptr != '\0') {
     KJ_IF_MAYBE(name, consumeHeaderName(ptr)) {
-      kj::StringPtr line = consumeLine(ptr);
+      bool sawFolding = false;
+      kj::StringPtr line = consumeLine(ptr, &sawFolding);
+      if (sawFolding) {
+        // Obsolete line folding (a continuation line beginning with 
whitespace). RFC 9112 section
+        // 7.1.4 says a server MUST either reject such a message with 400 (Bad 
Request) or replace
+        // the folding with spaces. Folding is never used legitimately and has 
historically been a
+        // source of HTTP desync, so we reject.
+        return false;
+      }
       addNoCheck(*name, line);
     } else {
       return false;
@@ -1045,18 +1096,22 @@
 kj::String HttpHeaders::serializeRequest(
     HttpMethod method, kj::StringPtr url,
     kj::ArrayPtr<const kj::StringPtr> connectionHeaders) const {
+  requireValidRequestUrl(url);
   return serialize(kj::toCharSequence(method), url, kj::StringPtr("HTTP/1.1"), 
connectionHeaders);
 }
 
 kj::String HttpHeaders::serializeConnectRequest(
     kj::StringPtr authority,
     kj::ArrayPtr<const kj::StringPtr> connectionHeaders) const {
+  requireValidRequestUrl(authority);
   return serialize("CONNECT"_kj, authority, kj::StringPtr("HTTP/1.1"), 
connectionHeaders);
 }
 
 kj::String HttpHeaders::serializeResponse(
     uint statusCode, kj::StringPtr statusText,
     kj::ArrayPtr<const kj::StringPtr> connectionHeaders) const {
+  requireValidStatusText(statusText);
+
   auto statusCodeStr = kj::toCharSequence(statusCode);
 
   return serialize(kj::StringPtr("HTTP/1.1"), statusCodeStr, statusText, 
connectionHeaders);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/kj/compat/tls.c++ 
new/capnproto-c++-1.5.0/src/kj/compat/tls.c++
--- old/capnproto-c++-1.4.0/src/kj/compat/tls.c++       2025-12-16 
23:16:27.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/kj/compat/tls.c++       2026-07-10 
00:33:53.000000000 +0200
@@ -1125,13 +1125,14 @@
     KJ_FAIL_REQUIRE("client did not provide a certificate") { return nullptr; }
   }
 
-  X509_NAME* subj = X509_get_subject_name(reinterpret_cast<X509*>(cert));
+  const X509_NAME* subj = X509_get_subject_name(reinterpret_cast<X509*>(cert));
 
-  int index = X509_NAME_get_index_by_NID(subj, NID_commonName, -1);
+  // Cast away const for compatibility with older OpenSSL versions
+  int index = X509_NAME_get_index_by_NID(const_cast<X509_NAME*>(subj), 
NID_commonName, -1);
   KJ_ASSERT(index != -1, "certificate has no common name?");
-  X509_NAME_ENTRY* entry = X509_NAME_get_entry(subj, index);
+  const X509_NAME_ENTRY* entry = X509_NAME_get_entry(subj, index);
   KJ_ASSERT(entry != nullptr);
-  ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry);
+  const ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry);
   KJ_ASSERT(data != nullptr);
 
   unsigned char* out = nullptr;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/kj/debug-test.c++ 
new/capnproto-c++-1.5.0/src/kj/debug-test.c++
--- old/capnproto-c++-1.4.0/src/kj/debug-test.c++       2025-12-16 
23:16:27.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/kj/debug-test.c++       2026-07-10 
00:33:53.000000000 +0200
@@ -46,6 +46,13 @@
 
 class MockException {};
 
+struct ThrowOnStringify {};
+kj::String KJ_STRINGIFY(ThrowOnStringify) {
+  // Simulates a parameter whose stringification throws an exception (e.g. 
reading a corrupt
+  // Cap'n Proto field). Used to test that KJ_CONTEXT handles this gracefully.
+  KJ_FAIL_ASSERT("stringification intentionally failed") { return nullptr; }
+}
+
 class MockExceptionCallback: public ExceptionCallback {
 public:
   ~MockExceptionCallback() {}
@@ -463,6 +470,25 @@
   ));
 }
 
+KJ_TEST("KJ_CONTEXT parameter that throws during evaluation is dropped") {
+  // Regression test: previously, if evaluating a KJ_CONTEXT parameter threw 
an exception (e.g.
+  // stringifying a corrupt value), that exception would re-enter the same 
Context callback, which
+  // would re-evaluate the parameter, throwing again, ... leading to infinite 
recursion and a
+  // stack overflow. Now, if evaluating the context throws, the context is 
simply dropped and the
+  // original exception propagates normally.
+  auto exception = kj::runCatchingExceptions([&]() {
+    KJ_CONTEXT("bad context", ThrowOnStringify());
+    KJ_FAIL_ASSERT("the real error") { break; }
+  });
+
+  auto& e = KJ_ASSERT_NONNULL(exception);
+  auto text = kj::str(e);
+  // The real error still propagates...
+  KJ_EXPECT(strstr(text.cStr(), "the real error") != nullptr, text);
+  // ...but the context that failed to evaluate was dropped.
+  KJ_EXPECT(strstr(text.cStr(), "bad context") == nullptr, text);
+}
+
 KJ_TEST("magic assert stringification") {
   {
     auto exception = KJ_ASSERT_NONNULL(kj::runCatchingExceptions([&]() {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/kj/debug.c++ 
new/capnproto-c++-1.5.0/src/kj/debug.c++
--- old/capnproto-c++-1.4.0/src/kj/debug.c++    2025-12-16 23:16:27.000000000 
+0100
+++ new/capnproto-c++-1.5.0/src/kj/debug.c++    2026-07-10 00:33:53.000000000 
+0200
@@ -441,32 +441,63 @@
 Debug::Context::Context(): logged(false) {}
 Debug::Context::~Context() noexcept(false) {}
 
-Debug::Context::Value Debug::Context::ensureInitialized() {
+Maybe<Debug::Context::Value> Debug::Context::ensureInitialized() {
+  if (evaluationFailed || evaluating) {
+    // Either a previous evaluation attempt threw, or we are being called 
re-entrantly from within
+    // evaluate() itself (because evaluating the context parameters threw an 
exception, which
+    // re-entered the exception callback chain -- see the comments in 
debug.h). In either case we
+    // must drop the context to avoid infinite recursion / stack overflow.
+    evaluationFailed = true;
+    return nullptr;
+  }
+
+  if (value == nullptr) {
+    // Evaluating the context parameters could itself throw (e.g. if a 
parameter's stringification
+    // throws). We must catch such exceptions here; otherwise the thrown 
exception would re-enter
+    // this same Context callback, calling ensureInitialized() again, leading 
to infinite recursion
+    // and eventually a stack overflow. If evaluation throws, `value` won't be 
set and we'll drop
+    // the context below.
+    evaluating = true;
+    KJ_DEFER(evaluating = false);
+    auto e = kj::runCatchingExceptions([&]() {
+      value = evaluate();
+    });
+    if (e != nullptr) {
+      // In -fno-exceptions mode, a recoverable exception may have been thrown 
but we still
+      // proceeded to assing `value`. Discard it here to match the behavior if 
exceptions were
+      // enabled.
+      value = nullptr;
+    }
+  }
+
   KJ_IF_MAYBE(v, value) {
     return Value(v->file, v->line, heapString(v->description));
   } else {
-    Value result = evaluate();
-    value = Value(result.file, result.line, heapString(result.description));
-    return result;
+    // Our attempt to call `evaluate()` must have thrown an exception. Drop 
the context.
+    evaluationFailed = true;
+    return nullptr;
   }
 }
 
 void Debug::Context::onRecoverableException(Exception&& exception) {
-  Value v = ensureInitialized();
-  exception.wrapContext(v.file, v.line, mv(v.description));
+  KJ_IF_MAYBE(v, ensureInitialized()) {
+    exception.wrapContext(v->file, v->line, mv(v->description));
+  }
   next.onRecoverableException(kj::mv(exception));
 }
 void Debug::Context::onFatalException(Exception&& exception) {
-  Value v = ensureInitialized();
-  exception.wrapContext(v.file, v.line, mv(v.description));
+  KJ_IF_MAYBE(v, ensureInitialized()) {
+    exception.wrapContext(v->file, v->line, mv(v->description));
+  }
   next.onFatalException(kj::mv(exception));
 }
 void Debug::Context::logMessage(LogSeverity severity, const char* file, int 
line, int contextDepth,
                                 String&& text) {
   if (!logged) {
-    Value v = ensureInitialized();
-    next.logMessage(LogSeverity::INFO, trimSourceFilename(v.file).cStr(), 
v.line, 0,
-                    str("context: ", mv(v.description), '\n'));
+    KJ_IF_MAYBE(v, ensureInitialized()) {
+      next.logMessage(LogSeverity::INFO, trimSourceFilename(v->file).cStr(), 
v->line, 0,
+                      str("context: ", mv(v->description), '\n'));
+    }
     logged = true;
   }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/kj/debug.h 
new/capnproto-c++-1.5.0/src/kj/debug.h
--- old/capnproto-c++-1.4.0/src/kj/debug.h      2025-12-16 23:16:27.000000000 
+0100
+++ new/capnproto-c++-1.5.0/src/kj/debug.h      2026-07-10 00:33:53.000000000 
+0200
@@ -488,9 +488,20 @@
 
   private:
     bool logged;
+    bool evaluationFailed = false;
+    // Set true if an attempt to evaluate() the context threw an exception. 
Once this happens we
+    // permanently drop the context. This prevents re-evaluation, which could 
throw again, leading
+    // to infinite recursion: evaluate() throwing an exception re-enters the 
exception callback
+    // chain, which includes this very Context, so 
onFatalException()/onRecoverableException() would
+    // be invoked recursively.
+    bool evaluating = false;
+    // Set true while evaluate() is running, so that we can detect the 
re-entrant case described
+    // above and bail out.
     Maybe<Value> value;
 
-    Value ensureInitialized();
+    Maybe<Value> ensureInitialized();
+    // Evaluates the context (if not already evaluated) and returns its value. 
Returns kj::none if
+    // evaluating the context threw an exception, in which case the context 
should be dropped.
   };
 
   template <typename Func>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/kj/exception-test.c++ 
new/capnproto-c++-1.5.0/src/kj/exception-test.c++
--- old/capnproto-c++-1.4.0/src/kj/exception-test.c++   2025-12-16 
23:16:27.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/kj/exception-test.c++   2026-07-10 
00:33:53.000000000 +0200
@@ -294,6 +294,16 @@
       {8, 7, 6, 5, 6, 7, 8, 7, 8});
 }
 
+KJ_TEST("KJ_STRINGIFY(Exception::Type) handles out-of-range values") {
+  KJ_EXPECT(kj::str(kj::Exception::Type::FAILED) == "failed");
+  KJ_EXPECT(kj::str(kj::Exception::Type::OVERLOADED) == "overloaded");
+  KJ_EXPECT(kj::str(kj::Exception::Type::DISCONNECTED) == "disconnected");
+  KJ_EXPECT(kj::str(kj::Exception::Type::UNIMPLEMENTED) == "unimplemented");
+
+  KJ_EXPECT(kj::str(static_cast<kj::Exception::Type>(99)) == "failed");
+  KJ_EXPECT(kj::str(static_cast<kj::Exception::Type>(0xffff)) == "failed");
+}
+
 }  // namespace
 }  // namespace _ (private)
 }  // namespace kj
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/kj/exception.c++ 
new/capnproto-c++-1.5.0/src/kj/exception.c++
--- old/capnproto-c++-1.4.0/src/kj/exception.c++        2026-03-12 
14:11:58.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/kj/exception.c++        2026-07-10 
00:33:53.000000000 +0200
@@ -758,7 +758,11 @@
     "unimplemented"
   };
 
-  return TYPE_STRINGS[static_cast<uint>(type)];
+  uint i = static_cast<uint>(type);
+  if (i >= kj::size(TYPE_STRINGS)) {
+    i = 0;
+  }
+  return TYPE_STRINGS[i];
 }
 
 String KJ_STRINGIFY(const Exception& e) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/kj/filesystem-disk-win32.c++ 
new/capnproto-c++-1.5.0/src/kj/filesystem-disk-win32.c++
--- old/capnproto-c++-1.4.0/src/kj/filesystem-disk-win32.c++    2025-12-16 
23:16:27.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/kj/filesystem-disk-win32.c++    2026-07-10 
00:33:53.000000000 +0200
@@ -380,6 +380,11 @@
       case ERROR_CALL_NOT_IMPLEMENTED:
         // Probably WINE.
        break;
+      case ERROR_INVALID_FUNCTION:
+        // Also WINE: NtQueryInformationFile returns STATUS_NOT_IMPLEMENTED for
+        // unsupported FileInfoClass values, which RtlNtStatusToDosError maps 
to
+        // ERROR_INVALID_FUNCTION (not ERROR_CALL_NOT_IMPLEMENTED).
+        break;
       case ERROR_INVALID_PARAMETER:
         // Probably VeraCrypt. See 
https://github.com/capnproto/capnproto/issues/2176
         break;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/kj/filesystem-test.c++ 
new/capnproto-c++-1.5.0/src/kj/filesystem-test.c++
--- old/capnproto-c++-1.4.0/src/kj/filesystem-test.c++  2025-12-16 
23:16:27.000000000 +0100
+++ new/capnproto-c++-1.5.0/src/kj/filesystem-test.c++  2026-07-10 
00:33:53.000000000 +0200
@@ -155,7 +155,7 @@
   KJ_EXPECT_THROW_MESSAGE("root path has no parent", Path(nullptr).parent());
 }
 
-constexpr kj::ArrayPtr<const wchar_t> operator "" _a(const wchar_t* str, 
size_t n) {
+constexpr kj::ArrayPtr<const wchar_t> operator ""_a(const wchar_t* str, size_t 
n) {
   return { str, n };
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/capnproto-c++-1.4.0/src/kj/string.h 
new/capnproto-c++-1.5.0/src/kj/string.h
--- old/capnproto-c++-1.4.0/src/kj/string.h     2025-12-16 23:16:27.000000000 
+0100
+++ new/capnproto-c++-1.5.0/src/kj/string.h     2026-07-10 00:33:53.000000000 
+0200
@@ -37,7 +37,7 @@
   class StringTree;   // string-tree.h
 }
 
-constexpr kj::StringPtr operator "" _kj(const char* str, size_t n);
+constexpr kj::StringPtr operator ""_kj(const char* str, size_t n);
 // You can append _kj to a string literal to make its type be StringPtr. There 
are a few cases
 // where you must do this for correctness:
 // - When you want to declare a constexpr StringPtr. Without _kj, this is a 
compile error.
@@ -53,7 +53,7 @@
 // string literal vs. one with _kj (assuming the compiler is able to optimize 
away strlen() on a
 // string literal).
 
-constexpr kj::LiteralStringConst operator "" _kjc(const char* str, size_t n);
+constexpr kj::LiteralStringConst operator ""_kjc(const char* str, size_t n);
 
 namespace kj {
 
@@ -176,7 +176,7 @@
 
 private:
   inline explicit constexpr StringPtr(ArrayPtr<const char> content): 
content(content) {}
-  friend constexpr StringPtr (::operator "" _kj)(const char* str, size_t n);
+  friend constexpr StringPtr (::operator ""_kj)(const char* str, size_t n);
   friend class LiteralStringConst;
 
   ArrayPtr<const char> content;
@@ -222,7 +222,7 @@
 
 private:
   inline explicit constexpr LiteralStringConst(ArrayPtr<const char> content): 
StringPtr(content) {}
-  friend constexpr LiteralStringConst (::operator "" _kjc)(const char* str, 
size_t n);
+  friend constexpr LiteralStringConst (::operator ""_kjc)(const char* str, 
size_t n);
 };
 
 // 
=======================================================================================
@@ -924,11 +924,11 @@
 
 }  // namespace kj
 
-constexpr kj::StringPtr operator "" _kj(const char* str, size_t n) {
+constexpr kj::StringPtr operator ""_kj(const char* str, size_t n) {
   return kj::StringPtr(kj::ArrayPtr<const char>(str, n + 1));
 };
 
-constexpr kj::LiteralStringConst operator "" _kjc(const char* str, size_t n) {
+constexpr kj::LiteralStringConst operator ""_kjc(const char* str, size_t n) {
   return kj::LiteralStringConst(kj::ArrayPtr<const char>(str, n + 1));
 };
 

Reply via email to