Your message dated Sat, 11 Jul 2026 10:32:48 +0000
with message-id <[email protected]>
and subject line Released in 13.6
has caused the Debian Bug report #1141310,
regarding trixie-pu: package protobuf/3.21.12-11+deb13u1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
1141310: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1141310
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected], [email protected]
Control: affects -1 + src:protobuf
User: [email protected]
Usertags: pu

  * Fix CVE-2026-0994: JSON recursion depth bypass (closes: #1126302).
  * Fix CVE-2026-6409: PHP Denial of Service (closes: #1134895).
  * Complete fix of CVE-2024-7254 (closes: #1082381):
    - add recursion checks and recursion limit,
    - add tests.
  * Fix CVE-2025-4565: data containing an arbitrary number of recursive
    groups, recursive messages or a series of SGROUP tags can be corrupted
    by exceeding the Python recursion limit (closes: #1108057).
diffstat for protobuf-3.21.12 protobuf-3.21.12

 changelog                                                               |   18 
 patches/0001-Fix-Any-recursion-depth-bypass-in-Python-json_format.patch |  169 
++
 patches/0002-Check-that-readRaw-does-not-accept-negative-length-v.patch |   48 
 patches/0003-php-Fix-that-recursion-limit-is-not-enforced.patch         |   65 
 patches/CVE-2024-7254-1.patch                                           |  202 
++
 patches/CVE-2024-7254-2.patch                                           |  143 
++
 patches/CVE-2024-7254-3.patch                                           |  684 
++++++++++
 patches/CVE-2024-7254-4.patch                                           |   21 
 patches/CVE-2024-7254-5.patch                                           |   66 
 patches/CVE-2024-7254.patch                                             |  143 
--
 patches/CVE-2025-4565-1.patch                                           |  117 
+
 patches/CVE-2025-4565-2.patch                                           |  395 
+++++
 patches/CVE-2025-4565-3.patch                                           |  207 
+++
 patches/series                                                          |   12 
 14 files changed, 2146 insertions(+), 144 deletions(-)

diff -Nru protobuf-3.21.12/debian/changelog protobuf-3.21.12/debian/changelog
--- protobuf-3.21.12/debian/changelog   2025-04-29 22:27:02.000000000 +0300
+++ protobuf-3.21.12/debian/changelog   2026-07-02 22:28:07.000000000 +0300
@@ -1,3 +1,21 @@
+protobuf (3.21.12-11+deb13u1) trixie; urgency=medium
+
+  * Non-maintainer upload.
+  * Fix CVE-2026-0994: JSON recursion depth bypass (closes: #1126302).
+  * Fix CVE-2026-6409: PHP Denial of Service (closes: #1134895).
+
+  [ Hlib Korzhynskyy <[email protected]> ]
+  * Complete fix of CVE-2024-7254 (closes: #1082381):
+    - add recursion checks and recursion limit,
+    - add tests.
+
+  [ Laszlo Boszormenyi (GCS) ]
+  * Fix CVE-2025-4565: data containing an arbitrary number of recursive
+    groups, recursive messages or a series of SGROUP tags can be corrupted
+    by exceeding the Python recursion limit (closes: #1108057).
+
+ -- Adrian Bunk <[email protected]>  Thu, 02 Jul 2026 22:28:07 +0300
+
 protobuf (3.21.12-11) unstable; urgency=high
 
   * Fix CVE-2024-7254: when parsing unknown fields in the Protobuf Java Lite
diff -Nru 
protobuf-3.21.12/debian/patches/0001-Fix-Any-recursion-depth-bypass-in-Python-json_format.patch
 
protobuf-3.21.12/debian/patches/0001-Fix-Any-recursion-depth-bypass-in-Python-json_format.patch
--- 
protobuf-3.21.12/debian/patches/0001-Fix-Any-recursion-depth-bypass-in-Python-json_format.patch
     1970-01-01 02:00:00.000000000 +0200
+++ 
protobuf-3.21.12/debian/patches/0001-Fix-Any-recursion-depth-bypass-in-Python-json_format.patch
     2026-07-02 22:07:59.000000000 +0300
@@ -0,0 +1,169 @@
+From 425bbbbb1bba4f76cbae984b75fefbc84666d801 Mon Sep 17 00:00:00 2001
+From: zhangskz <[email protected]>
+Date: Thu, 29 Jan 2026 16:32:56 -0500
+Subject: Fix Any recursion depth bypass in Python json_format.ParseDict
+ (#25239) (#25587)
+
+This fixes a security vulnerability where nested google.protobuf.Any messages 
could bypass the max_recursion_depth limit, potentially leading to denial of 
service via stack overflow.
+
+The root cause was that _ConvertAnyMessage() was calling itself recursively 
via methodcaller() for nested well-known types, bypassing the recursion depth 
tracking in ConvertMessage().
+
+The fix routes well-known type parsing through ConvertMessage() to ensure 
proper recursion depth accounting for all message types including nested Any.
+
+Fixes #25070
+
+Closes #25239
+
+COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/25239
 from aviralgarg05:fix-any-recursion-depth-bypass 
3cbbcbea142593d3afd2ceba2db14b05660f62f4
+PiperOrigin-RevId: 862740421
+
+Co-authored-by: Aviral Garg <[email protected]>
+---
+ .../protobuf/internal/json_format_test.py     | 101 ++++++++++++++++++
+ python/google/protobuf/json_format.py         |  12 ++-
+ 2 files changed, 110 insertions(+), 3 deletions(-)
+
+diff --git a/python/google/protobuf/internal/json_format_test.py 
b/python/google/protobuf/internal/json_format_test.py
+index 7b7d3bba4..8eb9dfd0a 100644
+--- a/python/google/protobuf/internal/json_format_test.py
++++ b/python/google/protobuf/internal/json_format_test.py
+@@ -1281,5 +1281,106 @@ class JsonFormatTest(JsonFormatBase):
+     json_format.Parse('{"payload": {}, "child": {"child":{}}}',
+                       message, max_recursion_depth=3)
+ 
++  def testAnyRecursionDepthEnforcement(self):
++    """Test that nested Any messages respect max_recursion_depth limit."""
++    # Test that deeply nested Any messages raise ParseError instead of
++    # bypassing the recursion limit. This prevents DoS via nested Any.
++    message = any_pb2.Any()
++
++    # Create nested Any structure that should exceed depth limit
++    # With max_recursion_depth=5, we can nest 4 Any messages
++    # (depth 1 = outer Any, depth 2-4 = nested Anys, depth 5 = final value)
++    nested_any = {
++        '@type': 'type.googleapis.com/google.protobuf.Any',
++        'value': {
++            '@type': 'type.googleapis.com/google.protobuf.Any',
++            'value': {
++                '@type': 'type.googleapis.com/google.protobuf.Any',
++                'value': {
++                    '@type': 'type.googleapis.com/google.protobuf.Any',
++                    'value': {
++                        '@type': 'type.googleapis.com/google.protobuf.Any',
++                        'value': {},
++                    },
++                },
++            },
++        },
++    }
++
++    # Should raise ParseError due to exceeding max depth, not RecursionError
++    self.assertRaisesRegex(
++        json_format.ParseError,
++        'Message too deep. Max recursion depth is 5',
++        json_format.ParseDict,
++        nested_any,
++        message,
++        max_recursion_depth=5,
++    )
++
++    # Verify that Any messages within the limit can be parsed successfully
++    # With max_recursion_depth=5, we can nest up to 4 Any messages
++    shallow_any = {
++        '@type': 'type.googleapis.com/google.protobuf.Any',
++        'value': {
++            '@type': 'type.googleapis.com/google.protobuf.Any',
++            'value': {
++                '@type': 'type.googleapis.com/google.protobuf.Any',
++                'value': {
++                    '@type': 'type.googleapis.com/google.protobuf.Any',
++                    'value': {},
++                },
++            },
++        },
++    }
++    json_format.ParseDict(shallow_any, message, max_recursion_depth=5)
++
++  def testAnyRecursionDepthBoundary(self):
++    """Test recursion depth boundary behavior (exclusive upper limit)."""
++    message = any_pb2.Any()
++
++    # Create nested Any at depth exactly 4 (should succeed with 
max_recursion_depth=5)
++    depth_4_any = {
++        '@type': 'type.googleapis.com/google.protobuf.Any',
++        'value': {
++            '@type': 'type.googleapis.com/google.protobuf.Any',
++            'value': {
++                '@type': 'type.googleapis.com/google.protobuf.Any',
++                'value': {
++                    '@type': 'type.googleapis.com/google.protobuf.Any',
++                    'value': {},
++                },
++            },
++        },
++    }
++    # This should succeed: depth 4 < max_recursion_depth 5
++    json_format.ParseDict(depth_4_any, message, max_recursion_depth=5)
++
++    # Create nested Any at depth exactly 5 (should fail with 
max_recursion_depth=5)
++    depth_5_any = {
++        '@type': 'type.googleapis.com/google.protobuf.Any',
++        'value': {
++            '@type': 'type.googleapis.com/google.protobuf.Any',
++            'value': {
++                '@type': 'type.googleapis.com/google.protobuf.Any',
++                'value': {
++                    '@type': 'type.googleapis.com/google.protobuf.Any',
++                    'value': {
++                        '@type': 'type.googleapis.com/google.protobuf.Any',
++                        'value': {},
++                    },
++                },
++            },
++        },
++    }
++    # This should fail: depth 5 == max_recursion_depth 5 (exclusive limit)
++    self.assertRaisesRegex(
++        json_format.ParseError,
++        'Message too deep. Max recursion depth is 5',
++        json_format.ParseDict,
++        depth_5_any,
++        message,
++        max_recursion_depth=5,
++    )
++
+ if __name__ == '__main__':
+   unittest.main()
+diff --git a/python/google/protobuf/json_format.py 
b/python/google/protobuf/json_format.py
+index 5024ed89d..ff7e3c6e5 100644
+--- a/python/google/protobuf/json_format.py
++++ b/python/google/protobuf/json_format.py
+@@ -486,6 +486,10 @@ class _Parser(object):
+     Raises:
+       ParseError: In case of convert problems.
+     """
++    # Increment recursion depth at message entry. The max_recursion_depth 
limit
++    # is exclusive: a depth value equal to max_recursion_depth will trigger an
++    # error. For example, with max_recursion_depth=5, nesting up to depth 4 is
++    # allowed, but attempting depth 5 raises ParseError.
+     self.recursion_depth += 1
+     if self.recursion_depth > self.max_recursion_depth:
+       raise ParseError('Message too deep. Max recursion depth is {0}'.format(
+@@ -652,9 +656,11 @@ class _Parser(object):
+       self._ConvertWrapperMessage(value['value'], sub_message,
+                                   '{0}.value'.format(path))
+     elif full_name in _WKTJSONMETHODS:
+-      methodcaller(_WKTJSONMETHODS[full_name][1], value['value'], sub_message,
+-                   '{0}.value'.format(path))(
+-                       self)
++      # For well-known types (including nested Any), use ConvertMessage
++      # to ensure recursion depth is properly tracked
++      self.ConvertMessage(
++          value['value'], sub_message, '{0}.value'.format(path)
++      )
+     else:
+       del value['@type']
+       self._ConvertFieldValuePair(value, sub_message, path)
+-- 
+2.47.3
+
diff -Nru 
protobuf-3.21.12/debian/patches/0002-Check-that-readRaw-does-not-accept-negative-length-v.patch
 
protobuf-3.21.12/debian/patches/0002-Check-that-readRaw-does-not-accept-negative-length-v.patch
--- 
protobuf-3.21.12/debian/patches/0002-Check-that-readRaw-does-not-accept-negative-length-v.patch
     1970-01-01 02:00:00.000000000 +0200
+++ 
protobuf-3.21.12/debian/patches/0002-Check-that-readRaw-does-not-accept-negative-length-v.patch
     2026-07-02 22:07:59.000000000 +0300
@@ -0,0 +1,48 @@
+From 8d3c56f84a1158095f28ef859757872df6c176cc Mon Sep 17 00:00:00 2001
+From: Protobuf Team Bot <[email protected]>
+Date: Tue, 13 Jan 2026 12:31:18 -0800
+Subject: Check that `readRaw` does not accept negative length value.
+
+Fixes https://github.com/protocolbuffers/protobuf/issues/24159
+
+PiperOrigin-RevId: 855837030
+---
+ php/src/Google/Protobuf/Internal/CodedInputStream.php | 3 ++-
+ php/tests/EncodeDecodeTest.php                        | 7 +++++++
+ 2 files changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/php/src/Google/Protobuf/Internal/CodedInputStream.php 
b/php/src/Google/Protobuf/Internal/CodedInputStream.php
+index 2ed2dfde2..0f98be7a6 100644
+--- a/php/src/Google/Protobuf/Internal/CodedInputStream.php
++++ b/php/src/Google/Protobuf/Internal/CodedInputStream.php
+@@ -295,7 +295,8 @@ class CodedInputStream
+     public function readRaw($size, &$buffer)
+     {
+         $current_buffer_size = 0;
+-        if ($this->bufferSize() < $size) {
++        // size (varint) read from the wire could be negative.
++        if ($size < 0 || $this->bufferSize() < $size) {
+             return false;
+         }
+ 
+diff --git a/php/tests/EncodeDecodeTest.php b/php/tests/EncodeDecodeTest.php
+index 33d8da179..ddd01a1ac 100644
+--- a/php/tests/EncodeDecodeTest.php
++++ b/php/tests/EncodeDecodeTest.php
+@@ -538,6 +538,13 @@ class EncodeDecodeTest extends TestBase
+         $this->assertEquals(-1, $m->getOptionalInt32());
+     }
+ 
++    public function testInvalidVarintLength() {
++        $this->expectException(Exception::class);
++
++        $m = new TestMessage();
++        $m->mergeFromString(hex2bin("0afaffffff0f"));
++    }
++
+     public function testRandomFieldOrder()
+     {
+         $m = new TestRandomFieldOrder();
+-- 
+2.47.3
+
diff -Nru 
protobuf-3.21.12/debian/patches/0003-php-Fix-that-recursion-limit-is-not-enforced.patch
 
protobuf-3.21.12/debian/patches/0003-php-Fix-that-recursion-limit-is-not-enforced.patch
--- 
protobuf-3.21.12/debian/patches/0003-php-Fix-that-recursion-limit-is-not-enforced.patch
     1970-01-01 02:00:00.000000000 +0200
+++ 
protobuf-3.21.12/debian/patches/0003-php-Fix-that-recursion-limit-is-not-enforced.patch
     2026-07-02 22:07:59.000000000 +0300
@@ -0,0 +1,65 @@
+From 16db0faafd1c7357a7d91e53dc7deea10e9bbab9 Mon Sep 17 00:00:00 2001
+From: Protobuf Team Bot <[email protected]>
+Date: Wed, 14 Jan 2026 11:09:03 -0800
+Subject: php: Fix that recursion limit is not enforced.
+
+https://github.com/protocolbuffers/protobuf/issues/25067
+
+PiperOrigin-RevId: 856286406
+---
+ .../Protobuf/Internal/CodedInputStream.php    |  2 +-
+ php/tests/EncodeDecodeTest.php                | 25 +++++++++++++++++++
+ 2 files changed, 26 insertions(+), 1 deletion(-)
+
+diff --git a/php/src/Google/Protobuf/Internal/CodedInputStream.php 
b/php/src/Google/Protobuf/Internal/CodedInputStream.php
+index 0f98be7a6..52e8f5473 100644
+--- a/php/src/Google/Protobuf/Internal/CodedInputStream.php
++++ b/php/src/Google/Protobuf/Internal/CodedInputStream.php
+@@ -362,7 +362,7 @@ class CodedInputStream
+         $byte_limit, &$old_limit, &$recursion_budget)
+     {
+         $old_limit = $this->pushLimit($byte_limit);
+-        $recursion_limit = --$this->recursion_limit;
++        $recursion_budget = --$this->recursion_budget;
+     }
+ 
+     public function decrementRecursionDepthAndPopLimit($byte_limit)
+diff --git a/php/tests/EncodeDecodeTest.php b/php/tests/EncodeDecodeTest.php
+index ddd01a1ac..e4889aefc 100644
+--- a/php/tests/EncodeDecodeTest.php
++++ b/php/tests/EncodeDecodeTest.php
+@@ -545,6 +545,31 @@ class EncodeDecodeTest extends TestBase
+         $m->mergeFromString(hex2bin("0afaffffff0f"));
+     }
+ 
++    private function makeRecursiveMessage($depth) {
++        $m = new TestMessage();
++        $m->setOptionalInt32(1);
++        if ($depth == 0) {
++            return $m;
++        }
++        $m->setRecursive($this->makeRecursiveMessage($depth - 1));
++        return $m;
++    }
++
++    public function testRecursiveMessage() {
++        $payload = $this->makeRecursiveMessage(99)->serializeToString();
++
++        $m = new TestMessage();
++        $m->mergeFromString($payload);
++    }
++
++    public function testOverlyRecursiveMessage() {
++        $this->expectException(Exception::class);
++        $payload = $this->makeRecursiveMessage(101)->serializeToString();
++
++        $m = new TestMessage();
++        $m->mergeFromString($payload);
++    }
++
+     public function testRandomFieldOrder()
+     {
+         $m = new TestRandomFieldOrder();
+-- 
+2.47.3
+
diff -Nru protobuf-3.21.12/debian/patches/CVE-2024-7254-1.patch 
protobuf-3.21.12/debian/patches/CVE-2024-7254-1.patch
--- protobuf-3.21.12/debian/patches/CVE-2024-7254-1.patch       1970-01-01 
02:00:00.000000000 +0200
+++ protobuf-3.21.12/debian/patches/CVE-2024-7254-1.patch       2026-07-02 
22:07:33.000000000 +0300
@@ -0,0 +1,202 @@
+Backport of:
+
+From: Protobuf Team Bot <[email protected]>
+Date: Fri, 16 Aug 2024 16:57:47 -0700
+Subject: [PATCH 1/5] Internal change
+
+PiperOrigin-RevId: 663919912
+---
+ .../com/google/protobuf/CodedInputStream.java | 106 ++++--------------
+ .../com/google/protobuf/map_lite_test.proto   |   3 +-
+ .../proto/com/google/protobuf/map_test.proto  |   3 +-
+ .../java/com/google/protobuf/LiteTest.java    |   1 +
+ 4 files changed, 29 insertions(+), 84 deletions(-)
+
+Index: 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
++++ 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+@@ -246,13 +246,35 @@ public abstract class CodedInputStream {
+    * Reads and discards an entire message. This will read either until EOF or 
until an endgroup tag,
+    * whichever comes first.
+    */
+-  public abstract void skipMessage() throws IOException;
++  public void skipMessage() throws IOException {
++    while (true) {
++      final int tag = readTag();
++      if (tag == 0) {
++        return;
++      }
++      boolean fieldSkipped = skipField(tag);
++      if (!fieldSkipped) {
++        return;
++      }
++    }
++  }
+ 
+   /**
+    * Reads an entire message and writes it to output in wire format. This 
will read either until EOF
+    * or until an endgroup tag, whichever comes first.
+    */
+-  public abstract void skipMessage(CodedOutputStream output) throws 
IOException;
++  public void skipMessage(CodedOutputStream output) throws IOException {
++    while (true) {
++      final int tag = readTag();
++      if (tag == 0) {
++        return;
++      }
++      boolean fieldSkipped = skipField(tag, output);
++      if (!fieldSkipped) {
++        return;
++      }
++    }
++  }
+ 
+ 
+   // -----------------------------------------------------------------
+@@ -725,27 +747,6 @@ public abstract class CodedInputStream {
+       }
+     }
+ 
+-    @Override
+-    public void skipMessage() throws IOException {
+-      while (true) {
+-        final int tag = readTag();
+-        if (tag == 0 || !skipField(tag)) {
+-          return;
+-        }
+-      }
+-    }
+-
+-    @Override
+-    public void skipMessage(CodedOutputStream output) throws IOException {
+-      while (true) {
+-        final int tag = readTag();
+-        if (tag == 0 || !skipField(tag, output)) {
+-          return;
+-        }
+-      }
+-    }
+-
+-
+     // -----------------------------------------------------------------
+ 
+     @Override
+@@ -1440,27 +1441,6 @@ public abstract class CodedInputStream {
+       }
+     }
+ 
+-    @Override
+-    public void skipMessage() throws IOException {
+-      while (true) {
+-        final int tag = readTag();
+-        if (tag == 0 || !skipField(tag)) {
+-          return;
+-        }
+-      }
+-    }
+-
+-    @Override
+-    public void skipMessage(CodedOutputStream output) throws IOException {
+-      while (true) {
+-        final int tag = readTag();
+-        if (tag == 0 || !skipField(tag, output)) {
+-          return;
+-        }
+-      }
+-    }
+-
+-
+     // -----------------------------------------------------------------
+ 
+     @Override
+@@ -2208,26 +2188,6 @@ public abstract class CodedInputStream {
+       }
+     }
+ 
+-    @Override
+-    public void skipMessage() throws IOException {
+-      while (true) {
+-        final int tag = readTag();
+-        if (tag == 0 || !skipField(tag)) {
+-          return;
+-        }
+-      }
+-    }
+-
+-    @Override
+-    public void skipMessage(CodedOutputStream output) throws IOException {
+-      while (true) {
+-        final int tag = readTag();
+-        if (tag == 0 || !skipField(tag, output)) {
+-          return;
+-        }
+-      }
+-    }
+-
+     /** Collects the bytes skipped and returns the data in a ByteBuffer. */
+     private class SkippedDataSink implements RefillCallback {
+       private int lastPos = pos;
+@@ -3329,26 +3289,6 @@ public abstract class CodedInputStream {
+       }
+     }
+ 
+-    @Override
+-    public void skipMessage() throws IOException {
+-      while (true) {
+-        final int tag = readTag();
+-        if (tag == 0 || !skipField(tag)) {
+-          return;
+-        }
+-      }
+-    }
+-
+-    @Override
+-    public void skipMessage(CodedOutputStream output) throws IOException {
+-      while (true) {
+-        final int tag = readTag();
+-        if (tag == 0 || !skipField(tag, output)) {
+-          return;
+-        }
+-      }
+-    }
+-
+     // -----------------------------------------------------------------
+ 
+     @Override
+Index: 
protobuf-3.21.12/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto
+===================================================================
+--- 
protobuf-3.21.12.orig/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto
++++ 
protobuf-3.21.12/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto
+@@ -122,5 +122,6 @@ message ReservedAsMapFieldWithEnumValue
+ 
+ // https://github.com/protocolbuffers/protobuf/issues/9785
+ message MapContainer {
+-  map<string,string> my_map = 1;
++  map<string, string> my_map = 1;
++  map<uint32, string> m = 3;
+ }
+Index: 
protobuf-3.21.12/java/core/src/test/proto/com/google/protobuf/map_test.proto
+===================================================================
+--- 
protobuf-3.21.12.orig/java/core/src/test/proto/com/google/protobuf/map_test.proto
++++ 
protobuf-3.21.12/java/core/src/test/proto/com/google/protobuf/map_test.proto
+@@ -121,5 +121,6 @@ message ReservedAsMapFieldWithEnumValue
+ 
+ // https://github.com/protocolbuffers/protobuf/issues/9785
+ message MapContainer {
+-  map<string,string> my_map = 1;
++  map<string, string> my_map = 1;
++  map<uint32, string> m = 3;
+ }
+Index: 
protobuf-3.21.12/java/lite/src/test/java/com/google/protobuf/LiteTest.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/lite/src/test/java/com/google/protobuf/LiteTest.java
++++ protobuf-3.21.12/java/lite/src/test/java/com/google/protobuf/LiteTest.java
+@@ -51,6 +51,7 @@ import com.google.protobuf.UnittestLite.
+ import com.google.protobuf.UnittestLite.TestAllTypesLiteOrBuilder;
+ import com.google.protobuf.UnittestLite.TestHugeFieldNumbersLite;
+ import com.google.protobuf.UnittestLite.TestNestedExtensionLite;
++import map_lite_test.MapTestProto.MapContainer;
+ import map_lite_test.MapTestProto.TestMap;
+ import map_lite_test.MapTestProto.TestMap.MessageValue;
+ import protobuf_unittest.NestedExtensionLite;
diff -Nru protobuf-3.21.12/debian/patches/CVE-2024-7254-2.patch 
protobuf-3.21.12/debian/patches/CVE-2024-7254-2.patch
--- protobuf-3.21.12/debian/patches/CVE-2024-7254-2.patch       1970-01-01 
02:00:00.000000000 +0200
+++ protobuf-3.21.12/debian/patches/CVE-2024-7254-2.patch       2026-07-02 
22:07:33.000000000 +0300
@@ -0,0 +1,143 @@
+From 850fcce9176e2c9070614dab53537760498c926b Mon Sep 17 00:00:00 2001
+From: Protobuf Team Bot <[email protected]>
+Date: Thu, 18 Jul 2024 07:41:01 -0700
+Subject: [PATCH 2/5] Internal change
+
+PiperOrigin-RevId: 653615736
+---
+ .../core/src/main/java/com/google/protobuf/ArrayDecoders.java | 3 +--
+ .../com/google/protobuf/InvalidProtocolBufferException.java   | 2 +-
+ .../core/src/main/java/com/google/protobuf/MessageSchema.java | 3 +++
+ .../src/main/java/com/google/protobuf/MessageSetSchema.java   | 1 +
+ .../src/main/java/com/google/protobuf/UnknownFieldSchema.java | 3 +--
+ java/lite/src/test/java/com/google/protobuf/LiteTest.java     | 3 +++
+ src/google/protobuf/unittest_lite.proto                       | 4 ++++
+ 7 files changed, 14 insertions(+), 5 deletions(-)
+
+Index: 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
++++ 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
+@@ -47,8 +47,7 @@ import java.io.IOException;
+ @CheckReturnValue
+ final class ArrayDecoders {
+ 
+-  private ArrayDecoders() {
+-  }
++  private ArrayDecoders() {}
+ 
+   /**
+    * A helper used to return multiple values in a Java function. Java doesn't 
natively support
+Index: 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
++++ 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
+@@ -155,7 +155,7 @@ public class InvalidProtocolBufferExcept
+   static InvalidProtocolBufferException recursionLimitExceeded() {
+     return new InvalidProtocolBufferException(
+         "Protocol message had too many levels of nesting.  May be malicious.  
"
+-            + "Use CodedInputStream.setRecursionLimit() to increase the depth 
limit.");
++            + "Use setRecursionLimit() to increase the recursion depth 
limit.");
+   }
+ 
+   static InvalidProtocolBufferException sizeLimitExceeded() {
+Index: 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/MessageSchema.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/core/src/main/java/com/google/protobuf/MessageSchema.java
++++ 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/MessageSchema.java
+@@ -3946,6 +3946,7 @@ final class MessageSchema<T> implements
+               unknownFields = 
unknownFieldSchema.getBuilderFromMessage(message);
+             }
+             // Unknown field.
++
+             if (unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader)) {
+               continue;
+             }
+@@ -4321,6 +4322,7 @@ final class MessageSchema<T> implements
+               if (unknownFields == null) {
+                 unknownFields = 
unknownFieldSchema.getBuilderFromMessage(message);
+               }
++
+               if (!unknownFieldSchema.mergeOneFieldFrom(unknownFields, 
reader)) {
+                 return;
+               }
+@@ -4337,6 +4339,7 @@ final class MessageSchema<T> implements
+             if (unknownFields == null) {
+               unknownFields = 
unknownFieldSchema.getBuilderFromMessage(message);
+             }
++
+             if (!unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader)) 
{
+               return;
+             }
+Index: 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
++++ 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
+@@ -301,6 +301,7 @@ final class MessageSetSchema<T> implemen
+               reader, extension, extensionRegistry, extensions);
+           return true;
+         } else {
++
+           return unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader);
+         }
+       } else {
+Index: 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java
++++ 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java
+@@ -78,7 +78,6 @@ abstract class UnknownFieldSchema<T, B>
+   /** Marks unknown fields as immutable. */
+   abstract void makeImmutable(Object message);
+ 
+-  /** Merges one field into the unknown fields. */
+   final boolean mergeOneFieldFrom(B unknownFields, Reader reader) throws 
IOException {
+     int tag = reader.getTag();
+     int fieldNumber = WireFormat.getTagFieldNumber(tag);
+@@ -111,7 +110,7 @@ abstract class UnknownFieldSchema<T, B>
+     }
+   }
+ 
+-  final void mergeFrom(B unknownFields, Reader reader) throws IOException {
++  private final void mergeFrom(B unknownFields, Reader reader) throws 
IOException {
+     while (true) {
+       if (reader.getFieldNumber() == Reader.READ_DONE
+           || !mergeOneFieldFrom(unknownFields, reader)) {
+Index: 
protobuf-3.21.12/java/lite/src/test/java/com/google/protobuf/LiteTest.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/lite/src/test/java/com/google/protobuf/LiteTest.java
++++ protobuf-3.21.12/java/lite/src/test/java/com/google/protobuf/LiteTest.java
+@@ -33,12 +33,14 @@ package com.google.protobuf;
+ import static com.google.common.truth.Truth.assertThat;
+ import static com.google.common.truth.Truth.assertWithMessage;
+ import static java.util.Collections.singletonList;
++import static org.junit.Assert.assertThrows;
+ 
+ import com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
+ import com.google.protobuf.UnittestImportLite.ImportEnumLite;
+ import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
+ import com.google.protobuf.UnittestLite.ForeignEnumLite;
+ import com.google.protobuf.UnittestLite.ForeignMessageLite;
++import com.google.protobuf.UnittestLite.RecursiveGroup;
+ import com.google.protobuf.UnittestLite.RecursiveMessage;
+ import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+ import com.google.protobuf.UnittestLite.TestAllTypesLite;
+@@ -73,6 +75,7 @@ import java.util.ArrayList;
+ import java.util.Arrays;
+ import java.util.Iterator;
+ import java.util.List;
++import java.util.concurrent.atomic.AtomicBoolean;
+ import org.junit.Before;
+ import org.junit.Test;
+ import org.junit.runner.RunWith;
+Index: protobuf-3.21.12/src/google/protobuf/unittest_lite.proto
+===================================================================
+--- protobuf-3.21.12.orig/src/google/protobuf/unittest_lite.proto
++++ protobuf-3.21.12/src/google/protobuf/unittest_lite.proto
+@@ -518,3 +518,7 @@ message RecursiveMessage {
+   optional RecursiveMessage recurse = 1;
+   optional bytes payload = 2;
+ }
++
++message RecursiveGroup {
++  RecursiveGroup recurse = 1 [features.message_encoding = DELIMITED];
++}
diff -Nru protobuf-3.21.12/debian/patches/CVE-2024-7254-3.patch 
protobuf-3.21.12/debian/patches/CVE-2024-7254-3.patch
--- protobuf-3.21.12/debian/patches/CVE-2024-7254-3.patch       1970-01-01 
02:00:00.000000000 +0200
+++ protobuf-3.21.12/debian/patches/CVE-2024-7254-3.patch       2026-07-02 
22:07:33.000000000 +0300
@@ -0,0 +1,684 @@
+Backport of:
+
+From 4728531c162f2f9e8c2ca1add713cfee2db6be3b Mon Sep 17 00:00:00 2001
+From: Protobuf Team Bot <[email protected]>
+Date: Tue, 17 Sep 2024 12:03:36 -0700
+Subject: [PATCH 3/5] Add recursion check when parsing unknown fields in Java.
+
+PiperOrigin-RevId: 675657198
+---
+ .../com/google/protobuf/ArrayDecoders.java    |  28 +++
+ .../com/google/protobuf/CodedInputStream.java |   6 +
+ .../com/google/protobuf/MessageSchema.java    |  12 +-
+ .../com/google/protobuf/MessageSetSchema.java |   3 +-
+ .../google/protobuf/UnknownFieldSchema.java   |  29 ++-
+ .../google/protobuf/CodedInputStreamTest.java | 158 ++++++++++++
+ .../java/com/google/protobuf/LiteTest.java    | 232 ++++++++++++++++++
+ 7 files changed, 456 insertions(+), 12 deletions(-)
+
+Index: 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
++++ 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
+@@ -46,6 +46,10 @@ import java.io.IOException;
+  */
+ @CheckReturnValue
+ final class ArrayDecoders {
++  static final int DEFAULT_RECURSION_LIMIT = 100;
++
++  @SuppressWarnings("NonFinalStaticField")
++  private static volatile int recursionLimit = DEFAULT_RECURSION_LIMIT;
+ 
+   private ArrayDecoders() {}
+ 
+@@ -60,6 +64,7 @@ final class ArrayDecoders {
+     public long long1;
+     public Object object1;
+     public final ExtensionRegistryLite extensionRegistry;
++    public int recursionDepth;
+ 
+     Registers() {
+       this.extensionRegistry = ExtensionRegistryLite.getEmptyRegistry();
+@@ -267,7 +272,10 @@ final class ArrayDecoders {
+     if (length < 0 || length > limit - position) {
+       throw InvalidProtocolBufferException.truncatedMessage();
+     }
++    registers.recursionDepth++;
++    checkRecursionLimit(registers.recursionDepth);
+     schema.mergeFrom(msg, data, position, position + length, registers);
++    registers.recursionDepth--;
+     registers.object1 = msg;
+     return position + length;
+   }
+@@ -285,9 +293,12 @@ final class ArrayDecoders {
+     // A group field must has a MessageSchema (the only other subclass of 
Schema is MessageSetSchema
+     // and it can't be used in group fields).
+     final MessageSchema messageSchema = (MessageSchema) schema;
++    registers.recursionDepth++;
++    checkRecursionLimit(registers.recursionDepth);
+     // It's OK to directly use parseProto2Message since proto3 doesn't have 
group.
+     final int endPosition =
+         messageSchema.parseProto2Message(msg, data, position, limit, 
endGroup, registers);
++    registers.recursionDepth--;
+     registers.object1 = msg;
+     return endPosition;
+   }
+@@ -1048,6 +1059,8 @@ final class ArrayDecoders {
+         final UnknownFieldSetLite child = UnknownFieldSetLite.newInstance();
+         final int endGroup = (tag & ~0x7) | WireFormat.WIRETYPE_END_GROUP;
+         int lastTag = 0;
++        registers.recursionDepth++;
++        checkRecursionLimit(registers.recursionDepth);
+         while (position < limit) {
+           position = decodeVarint32(data, position, registers);
+           lastTag = registers.int1;
+@@ -1056,6 +1069,7 @@ final class ArrayDecoders {
+           }
+           position = decodeUnknownField(lastTag, data, position, limit, 
child, registers);
+         }
++        registers.recursionDepth--;
+         if (position > limit || lastTag != endGroup) {
+           throw InvalidProtocolBufferException.parseFailure();
+         }
+@@ -1102,4 +1116,18 @@ final class ArrayDecoders {
+         throw InvalidProtocolBufferException.invalidTag();
+     }
+   }
++
++  /**
++   * Set the maximum recursion limit that ArrayDecoders will allow. An 
exception will be thrown if
++   * the depth of the message exceeds this limit.
++   */
++  public static void setRecursionLimit(int limit) {
++    recursionLimit = limit;
++  }
++
++  private static void checkRecursionLimit(int depth) throws 
InvalidProtocolBufferException {
++    if (depth >= recursionLimit) {
++      throw InvalidProtocolBufferException.recursionLimitExceeded();
++    }
++  }
+ }
+Index: 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
++++ 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+@@ -252,7 +252,10 @@ public abstract class CodedInputStream {
+       if (tag == 0) {
+         return;
+       }
++      checkRecursionLimit();
++      ++recursionDepth;
+       boolean fieldSkipped = skipField(tag);
++      --recursionDepth;
+       if (!fieldSkipped) {
+         return;
+       }
+@@ -269,7 +272,10 @@ public abstract class CodedInputStream {
+       if (tag == 0) {
+         return;
+       }
++      checkRecursionLimit();
++      ++recursionDepth;
+       boolean fieldSkipped = skipField(tag, output);
++      --recursionDepth;
+       if (!fieldSkipped) {
+         return;
+       }
+Index: 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/MessageSchema.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/core/src/main/java/com/google/protobuf/MessageSchema.java
++++ 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/MessageSchema.java
+@@ -3946,8 +3946,8 @@ final class MessageSchema<T> implements
+               unknownFields = 
unknownFieldSchema.getBuilderFromMessage(message);
+             }
+             // Unknown field.
+-
+-            if (unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader)) {
++            if (unknownFieldSchema.mergeOneFieldFrom(
++                unknownFields, reader, /* currentDepth= */ 0)) {
+               continue;
+             }
+           }
+@@ -4322,8 +4322,8 @@ final class MessageSchema<T> implements
+               if (unknownFields == null) {
+                 unknownFields = 
unknownFieldSchema.getBuilderFromMessage(message);
+               }
+-
+-              if (!unknownFieldSchema.mergeOneFieldFrom(unknownFields, 
reader)) {
++              if (!unknownFieldSchema.mergeOneFieldFrom(
++                  unknownFields, reader, /* currentDepth= */ 0)) {
+                 return;
+               }
+               break;
+@@ -4339,8 +4339,8 @@ final class MessageSchema<T> implements
+             if (unknownFields == null) {
+               unknownFields = 
unknownFieldSchema.getBuilderFromMessage(message);
+             }
+-
+-            if (!unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader)) 
{
++            if (!unknownFieldSchema.mergeOneFieldFrom(
++                unknownFields, reader, /* currentDepth= */ 0)) {
+               return;
+             }
+           }
+Index: 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
++++ 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
+@@ -301,8 +301,7 @@ final class MessageSetSchema<T> implemen
+               reader, extension, extensionRegistry, extensions);
+           return true;
+         } else {
+-
+-          return unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader);
++          return unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader, 
/* currentDepth= */ 0);
+         }
+       } else {
+         return reader.skipField();
+Index: 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java
++++ 
protobuf-3.21.12/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java
+@@ -36,6 +36,11 @@ import java.io.IOException;
+ @CheckReturnValue
+ abstract class UnknownFieldSchema<T, B> {
+ 
++  static final int DEFAULT_RECURSION_LIMIT = 100;
++
++  @SuppressWarnings("NonFinalStaticField")
++  private static volatile int recursionLimit = DEFAULT_RECURSION_LIMIT;
++
+   /** Whether unknown fields should be dropped. */
+   abstract boolean shouldDiscardUnknownFields(Reader reader);
+ 
+@@ -78,7 +83,9 @@ abstract class UnknownFieldSchema<T, B>
+   /** Marks unknown fields as immutable. */
+   abstract void makeImmutable(Object message);
+ 
+-  final boolean mergeOneFieldFrom(B unknownFields, Reader reader) throws 
IOException {
++  /** Merges one field into the unknown fields. */
++  final boolean mergeOneFieldFrom(B unknownFields, Reader reader, int 
currentDepth)
++      throws IOException {
+     int tag = reader.getTag();
+     int fieldNumber = WireFormat.getTagFieldNumber(tag);
+     switch (WireFormat.getTagWireType(tag)) {
+@@ -97,7 +104,12 @@ abstract class UnknownFieldSchema<T, B>
+       case WireFormat.WIRETYPE_START_GROUP:
+         final B subFields = newBuilder();
+         int endGroupTag = WireFormat.makeTag(fieldNumber, 
WireFormat.WIRETYPE_END_GROUP);
+-        mergeFrom(subFields, reader);
++        currentDepth++;
++        if (currentDepth >= recursionLimit) {
++          throw InvalidProtocolBufferException.recursionLimitExceeded();
++        }
++        mergeFrom(subFields, reader, currentDepth);
++        currentDepth--;
+         if (endGroupTag != reader.getTag()) {
+           throw InvalidProtocolBufferException.invalidEndTag();
+         }
+@@ -110,10 +122,11 @@ abstract class UnknownFieldSchema<T, B>
+     }
+   }
+ 
+-  private final void mergeFrom(B unknownFields, Reader reader) throws 
IOException {
++  private final void mergeFrom(B unknownFields, Reader reader, int 
currentDepth)
++      throws IOException {
+     while (true) {
+       if (reader.getFieldNumber() == Reader.READ_DONE
+-          || !mergeOneFieldFrom(unknownFields, reader)) {
++          || !mergeOneFieldFrom(unknownFields, reader, currentDepth)) {
+         break;
+       }
+     }
+@@ -130,4 +143,12 @@ abstract class UnknownFieldSchema<T, B>
+   abstract int getSerializedSizeAsMessageSet(T message);
+ 
+   abstract int getSerializedSize(T unknowns);
++
++  /**
++   * Set the maximum recursion limit that ArrayDecoders will allow. An 
exception will be thrown if
++   * the depth of the message exceeds this limit.
++   */
++  public void setRecursionLimit(int limit) {
++    recursionLimit = limit;
++  }
+ }
+Index: 
protobuf-3.21.12/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
++++ 
protobuf-3.21.12/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
+@@ -33,6 +33,9 @@ package com.google.protobuf;
+ import static com.google.common.truth.Truth.assertThat;
+ import static com.google.common.truth.Truth.assertWithMessage;
+ import static org.junit.Assert.assertArrayEquals;
++
++import com.google.common.primitives.Bytes;
++import map_test.MapTestProto.MapContainer;
+ import protobuf_unittest.UnittestProto.BoolMessage;
+ import protobuf_unittest.UnittestProto.Int32Message;
+ import protobuf_unittest.UnittestProto.Int64Message;
+@@ -57,6 +60,13 @@ public class CodedInputStreamTest {
+ 
+   private static final int DEFAULT_BLOCK_SIZE = 4096;
+ 
++  private static final int GROUP_TAP = WireFormat.makeTag(3, 
WireFormat.WIRETYPE_START_GROUP);
++
++  private static final byte[] NESTING_SGROUP = generateSGroupTags();
++
++  private static final byte[] NESTING_SGROUP_WITH_INITIAL_BYTES = 
generateSGroupTagsForMapField();
++
++
+   private enum InputType {
+     ARRAY {
+       @Override
+@@ -139,6 +149,17 @@ public class CodedInputStreamTest {
+     return bytes;
+   }
+ 
++  private static byte[] generateSGroupTags() {
++    byte[] bytes = new byte[100000];
++    Arrays.fill(bytes, (byte) GROUP_TAP);
++    return bytes;
++  }
++
++  private static byte[] generateSGroupTagsForMapField() {
++    byte[] initialBytes = {18, 1, 75, 26, (byte) 198, (byte) 154, 12};
++    return Bytes.concat(initialBytes, NESTING_SGROUP);
++  }
++
+   /**
+    * An InputStream which limits the number of bytes it reads at a time. We 
use this to make sure
+    * that CodedInputStream doesn't screw up when reading in small blocks.
+@@ -684,6 +705,143 @@ public class CodedInputStreamTest {
+     }
+   }
+ 
++  @Test
++  public void testMaliciousRecursion_unknownFields() throws Exception {
++    Throwable thrown =
++        assertThrows(
++            InvalidProtocolBufferException.class,
++            () -> TestRecursiveMessage.parseFrom(NESTING_SGROUP));
++
++    assertThat(thrown).hasMessageThat().contains("Protocol message had too 
many levels of nesting");
++  }
++
++  @Test
++  public void testMaliciousRecursion_skippingUnknownField() throws Exception {
++    Throwable thrown =
++        assertThrows(
++            InvalidProtocolBufferException.class,
++            () ->
++                DiscardUnknownFieldsParser.wrap(TestRecursiveMessage.parser())
++                    .parseFrom(NESTING_SGROUP));
++
++    assertThat(thrown).hasMessageThat().contains("Protocol message had too 
many levels of nesting");
++  }
++
++  @Test
++  public void testMaliciousSGroupTagsWithMapField_fromInputStream() throws 
Exception {
++    Throwable parseFromThrown =
++        assertThrows(
++            InvalidProtocolBufferException.class,
++            () ->
++                MapContainer.parseFrom(
++                    new 
ByteArrayInputStream(NESTING_SGROUP_WITH_INITIAL_BYTES)));
++    Throwable mergeFromThrown =
++        assertThrows(
++            InvalidProtocolBufferException.class,
++            () ->
++                MapContainer.newBuilder()
++                    .mergeFrom(new 
ByteArrayInputStream(NESTING_SGROUP_WITH_INITIAL_BYTES)));
++
++    assertThat(parseFromThrown)
++        .hasMessageThat()
++        .contains("Protocol message had too many levels of nesting");
++    assertThat(mergeFromThrown)
++        .hasMessageThat()
++        .contains("Protocol message had too many levels of nesting");
++  }
++
++  @Test
++  public void testMaliciousSGroupTags_inputStream_skipMessage() throws 
Exception {
++    ByteArrayInputStream inputSteam = new 
ByteArrayInputStream(NESTING_SGROUP);
++    CodedInputStream input = CodedInputStream.newInstance(inputSteam);
++    CodedOutputStream output = CodedOutputStream.newInstance(new 
byte[NESTING_SGROUP.length]);
++
++    Throwable thrown = assertThrows(InvalidProtocolBufferException.class, 
input::skipMessage);
++    Throwable thrown2 =
++        assertThrows(InvalidProtocolBufferException.class, () -> 
input.skipMessage(output));
++
++    assertThat(thrown).hasMessageThat().contains("Protocol message had too 
many levels of nesting");
++    assertThat(thrown2)
++        .hasMessageThat()
++        .contains("Protocol message had too many levels of nesting");
++  }
++
++  @Test
++  public void testMaliciousSGroupTagsWithMapField_fromByteArray() throws 
Exception {
++    Throwable parseFromThrown =
++        assertThrows(
++            InvalidProtocolBufferException.class,
++            () -> MapContainer.parseFrom(NESTING_SGROUP_WITH_INITIAL_BYTES));
++    Throwable mergeFromThrown =
++        assertThrows(
++            InvalidProtocolBufferException.class,
++            () -> 
MapContainer.newBuilder().mergeFrom(NESTING_SGROUP_WITH_INITIAL_BYTES));
++
++    assertThat(parseFromThrown)
++        .hasMessageThat()
++        .contains("the input ended unexpectedly in the middle of a field");
++    assertThat(mergeFromThrown)
++        .hasMessageThat()
++        .contains("the input ended unexpectedly in the middle of a field");
++  }
++
++  @Test
++  public void testMaliciousSGroupTags_arrayDecoder_skipMessage() throws 
Exception {
++    CodedInputStream input = CodedInputStream.newInstance(NESTING_SGROUP);
++    CodedOutputStream output = CodedOutputStream.newInstance(new 
byte[NESTING_SGROUP.length]);
++
++    Throwable thrown = assertThrows(InvalidProtocolBufferException.class, 
input::skipMessage);
++    Throwable thrown2 =
++        assertThrows(InvalidProtocolBufferException.class, () -> 
input.skipMessage(output));
++
++    assertThat(thrown).hasMessageThat().contains("Protocol message had too 
many levels of nesting");
++    assertThat(thrown2)
++        .hasMessageThat()
++        .contains("Protocol message had too many levels of nesting");
++  }
++
++  @Test
++  public void testMaliciousSGroupTagsWithMapField_fromByteBuffer() throws 
Exception {
++    Throwable thrown =
++        assertThrows(
++            InvalidProtocolBufferException.class,
++            () -> 
MapContainer.parseFrom(ByteBuffer.wrap(NESTING_SGROUP_WITH_INITIAL_BYTES)));
++
++    assertThat(thrown)
++        .hasMessageThat()
++        .contains("the input ended unexpectedly in the middle of a field");
++  }
++
++  @Test
++  public void testMaliciousSGroupTags_byteBuffer_skipMessage() throws 
Exception {
++    CodedInputStream input = InputType.NIO_DIRECT.newDecoder(NESTING_SGROUP);
++    CodedOutputStream output = CodedOutputStream.newInstance(new 
byte[NESTING_SGROUP.length]);
++
++    Throwable thrown = assertThrows(InvalidProtocolBufferException.class, 
input::skipMessage);
++    Throwable thrown2 =
++        assertThrows(InvalidProtocolBufferException.class, () -> 
input.skipMessage(output));
++
++    assertThat(thrown).hasMessageThat().contains("Protocol message had too 
many levels of nesting");
++    assertThat(thrown2)
++        .hasMessageThat()
++        .contains("Protocol message had too many levels of nesting");
++  }
++
++  @Test
++  public void testMaliciousSGroupTags_iterableByteBuffer() throws Exception {
++    CodedInputStream input = InputType.ITER_DIRECT.newDecoder(NESTING_SGROUP);
++    CodedOutputStream output = CodedOutputStream.newInstance(new 
byte[NESTING_SGROUP.length]);
++
++    Throwable thrown = assertThrows(InvalidProtocolBufferException.class, 
input::skipMessage);
++    Throwable thrown2 =
++        assertThrows(InvalidProtocolBufferException.class, () -> 
input.skipMessage(output));
++
++    assertThat(thrown).hasMessageThat().contains("Protocol message had too 
many levels of nesting");
++    assertThat(thrown2)
++        .hasMessageThat()
++        .contains("Protocol message had too many levels of nesting");
++  }
++
+   private void checkSizeLimitExceeded(InvalidProtocolBufferException e) {
+     assertThat(e)
+         .hasMessageThat()
+Index: 
protobuf-3.21.12/java/lite/src/test/java/com/google/protobuf/LiteTest.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/lite/src/test/java/com/google/protobuf/LiteTest.java
++++ protobuf-3.21.12/java/lite/src/test/java/com/google/protobuf/LiteTest.java
+@@ -2461,6 +2461,211 @@ public class LiteTest {
+   }
+ 
+   @Test
++  public void testParseFromInputStream_concurrent_nestingUnknownGroups() 
throws Exception {
++    int numThreads = 200;
++    ArrayList<Thread> threads = new ArrayList<>();
++
++    ByteString byteString = generateNestingGroups(99);
++    AtomicBoolean thrown = new AtomicBoolean(false);
++
++    for (int i = 0; i < numThreads; i++) {
++      Thread thread =
++          new Thread(
++              () -> {
++                try {
++                  TestAllTypesLite unused = 
TestAllTypesLite.parseFrom(byteString);
++                } catch (IOException e) {
++                  if (e.getMessage().contains("Protocol message had too many 
levels of nesting")) {
++                    thrown.set(true);
++                  }
++                }
++              });
++      thread.start();
++      threads.add(thread);
++    }
++
++    for (Thread thread : threads) {
++      thread.join();
++    }
++
++    assertThat(thrown.get()).isFalse();
++  }
++
++  @Test
++  public void testParseFromInputStream_nestingUnknownGroups() throws 
IOException {
++    ByteString byteString = generateNestingGroups(99);
++
++    Throwable thrown =
++        assertThrows(
++            InvalidProtocolBufferException.class, () -> 
TestAllTypesLite.parseFrom(byteString));
++    assertThat(thrown)
++        .hasMessageThat()
++        .doesNotContain("Protocol message had too many levels of nesting");
++  }
++
++  @Test
++  public void testParseFromInputStream_nestingUnknownGroups_exception() 
throws IOException {
++    ByteString byteString = generateNestingGroups(100);
++
++    Throwable thrown =
++        assertThrows(
++            InvalidProtocolBufferException.class, () -> 
TestAllTypesLite.parseFrom(byteString));
++    assertThat(thrown).hasMessageThat().contains("Protocol message had too 
many levels of nesting");
++  }
++
++  @Test
++  public void testParseFromInputStream_setRecursionLimit_exception() throws 
IOException {
++    ByteString byteString = generateNestingGroups(199);
++    UnknownFieldSchema<?, ?> schema = SchemaUtil.unknownFieldSetLiteSchema();
++    schema.setRecursionLimit(200);
++
++    Throwable thrown =
++        assertThrows(
++            InvalidProtocolBufferException.class, () -> 
TestAllTypesLite.parseFrom(byteString));
++    assertThat(thrown)
++        .hasMessageThat()
++        .doesNotContain("Protocol message had too many levels of nesting");
++    schema.setRecursionLimit(UnknownFieldSchema.DEFAULT_RECURSION_LIMIT);
++  }
++
++  @Test
++  public void testParseFromBytes_concurrent_nestingUnknownGroups() throws 
Exception {
++    int numThreads = 200;
++    ArrayList<Thread> threads = new ArrayList<>();
++
++    ByteString byteString = generateNestingGroups(99);
++    AtomicBoolean thrown = new AtomicBoolean(false);
++
++    for (int i = 0; i < numThreads; i++) {
++      Thread thread =
++          new Thread(
++              () -> {
++                try {
++                  // Should pass in byte[] instead of ByteString to go into 
ArrayDecoders.
++                  TestAllTypesLite unused = 
TestAllTypesLite.parseFrom(byteString.toByteArray());
++                } catch (InvalidProtocolBufferException e) {
++                  if (e.getMessage().contains("Protocol message had too many 
levels of nesting")) {
++                    thrown.set(true);
++                  }
++                }
++              });
++      thread.start();
++      threads.add(thread);
++    }
++
++    for (Thread thread : threads) {
++      thread.join();
++    }
++
++    assertThat(thrown.get()).isFalse();
++  }
++
++  @Test
++  public void testParseFromBytes_nestingUnknownGroups() throws IOException {
++    ByteString byteString = generateNestingGroups(99);
++
++    Throwable thrown =
++        assertThrows(
++            InvalidProtocolBufferException.class,
++            () -> TestAllTypesLite.parseFrom(byteString.toByteArray()));
++    assertThat(thrown)
++        .hasMessageThat()
++        .doesNotContain("Protocol message had too many levels of nesting");
++  }
++
++  @Test
++  public void testParseFromBytes_nestingUnknownGroups_exception() throws 
IOException {
++    ByteString byteString = generateNestingGroups(100);
++
++    Throwable thrown =
++        assertThrows(
++            InvalidProtocolBufferException.class,
++            () -> TestAllTypesLite.parseFrom(byteString.toByteArray()));
++    assertThat(thrown).hasMessageThat().contains("Protocol message had too 
many levels of nesting");
++  }
++
++  @Test
++  public void testParseFromBytes_setRecursionLimit_exception() throws 
IOException {
++    ByteString byteString = generateNestingGroups(199);
++    ArrayDecoders.setRecursionLimit(200);
++
++    Throwable thrown =
++        assertThrows(
++            InvalidProtocolBufferException.class,
++            () -> TestAllTypesLite.parseFrom(byteString.toByteArray()));
++    assertThat(thrown)
++        .hasMessageThat()
++        .doesNotContain("Protocol message had too many levels of nesting");
++    ArrayDecoders.setRecursionLimit(ArrayDecoders.DEFAULT_RECURSION_LIMIT);
++  }
++
++  @Test
++  public void testParseFromBytes_recursiveMessages() throws Exception {
++    byte[] data99 = makeRecursiveMessage(99).toByteArray();
++    byte[] data100 = makeRecursiveMessage(100).toByteArray();
++
++    RecursiveMessage unused = RecursiveMessage.parseFrom(data99);
++    Throwable thrown =
++        assertThrows(
++            InvalidProtocolBufferException.class, () -> 
RecursiveMessage.parseFrom(data100));
++    assertThat(thrown).hasMessageThat().contains("Protocol message had too 
many levels of nesting");
++  }
++
++  @Test
++  public void testParseFromBytes_recursiveKnownGroups() throws Exception {
++    byte[] data99 = makeRecursiveGroup(99).toByteArray();
++    byte[] data100 = makeRecursiveGroup(100).toByteArray();
++
++    RecursiveGroup unused = RecursiveGroup.parseFrom(data99);
++    Throwable thrown =
++        assertThrows(InvalidProtocolBufferException.class, () -> 
RecursiveGroup.parseFrom(data100));
++    assertThat(thrown).hasMessageThat().contains("Protocol message had too 
many levels of nesting");
++  }
++
++  @Test
++  @SuppressWarnings("ProtoParseFromByteString")
++  public void testMaliciousSGroupTagsWithMapField_fromByteArray() throws 
Exception {
++    ByteString byteString = generateNestingGroups(102);
++
++    Throwable parseFromThrown =
++        assertThrows(
++            InvalidProtocolBufferException.class,
++            () -> MapContainer.parseFrom(byteString.toByteArray()));
++    Throwable mergeFromThrown =
++        assertThrows(
++            InvalidProtocolBufferException.class,
++            () -> 
MapContainer.newBuilder().mergeFrom(byteString.toByteArray()));
++
++    assertThat(parseFromThrown)
++        .hasMessageThat()
++        .contains("Protocol message had too many levels of nesting");
++    assertThat(mergeFromThrown)
++        .hasMessageThat()
++        .contains("Protocol message had too many levels of nesting");
++  }
++
++  @Test
++  public void testMaliciousSGroupTagsWithMapField_fromInputStream() throws 
Exception {
++    byte[] bytes = generateNestingGroups(101).toByteArray();
++
++    Throwable parseFromThrown =
++        assertThrows(
++            InvalidProtocolBufferException.class,
++            () -> MapContainer.parseFrom(new ByteArrayInputStream(bytes)));
++    Throwable mergeFromThrown =
++        assertThrows(
++            InvalidProtocolBufferException.class,
++            () -> MapContainer.newBuilder().mergeFrom(new 
ByteArrayInputStream(bytes)));
++
++    assertThat(parseFromThrown)
++        .hasMessageThat()
++        .contains("Protocol message had too many levels of nesting");
++    assertThat(mergeFromThrown)
++        .hasMessageThat()
++        .contains("Protocol message had too many levels of nesting");
++  }
++
++  @Test
+   public void testParseFromByteBuffer_extensions() throws Exception {
+     TestAllExtensionsLite message =
+         TestAllExtensionsLite.newBuilder()
+@@ -2816,4 +3021,31 @@ public class LiteTest {
+     }
+     return false;
+   }
++
++  private static ByteString generateNestingGroups(int num) throws IOException 
{
++    int groupTap = WireFormat.makeTag(3, WireFormat.WIRETYPE_START_GROUP);
++    ByteString.Output byteStringOutput = ByteString.newOutput();
++    CodedOutputStream codedOutput = 
CodedOutputStream.newInstance(byteStringOutput);
++    for (int i = 0; i < num; i++) {
++      codedOutput.writeInt32NoTag(groupTap);
++    }
++    codedOutput.flush();
++    return byteStringOutput.toByteString();
++  }
++
++  private static RecursiveMessage makeRecursiveMessage(int num) {
++    if (num == 0) {
++      return RecursiveMessage.getDefaultInstance();
++    } else {
++      return 
RecursiveMessage.newBuilder().setRecurse(makeRecursiveMessage(num - 1)).build();
++    }
++  }
++
++  private static RecursiveGroup makeRecursiveGroup(int num) {
++    if (num == 0) {
++      return RecursiveGroup.getDefaultInstance();
++    } else {
++      return RecursiveGroup.newBuilder().setRecurse(makeRecursiveGroup(num - 
1)).build();
++    }
++  }
+ }
diff -Nru protobuf-3.21.12/debian/patches/CVE-2024-7254-4.patch 
protobuf-3.21.12/debian/patches/CVE-2024-7254-4.patch
--- protobuf-3.21.12/debian/patches/CVE-2024-7254-4.patch       1970-01-01 
02:00:00.000000000 +0200
+++ protobuf-3.21.12/debian/patches/CVE-2024-7254-4.patch       2026-07-02 
22:07:33.000000000 +0300
@@ -0,0 +1,21 @@
+From f000b7e18fd6921ca02ea4b87608e8cadcb7b64f Mon Sep 17 00:00:00 2001
+From: Sandy Zhang <[email protected]>
+Date: Wed, 18 Sep 2024 14:57:16 -0400
+Subject: [PATCH 4/5] Fix merge conflict by adding optional label to proto2
+ unittest_lite.proto
+
+---
+ src/google/protobuf/unittest_lite.proto | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: protobuf-3.21.12/src/google/protobuf/unittest_lite.proto
+===================================================================
+--- protobuf-3.21.12.orig/src/google/protobuf/unittest_lite.proto
++++ protobuf-3.21.12/src/google/protobuf/unittest_lite.proto
+@@ -520,5 +520,5 @@ message RecursiveMessage {
+ }
+ 
+ message RecursiveGroup {
+-  RecursiveGroup recurse = 1 [features.message_encoding = DELIMITED];
++  optional RecursiveGroup recurse = 1 [features.message_encoding = DELIMITED];
+ }
diff -Nru protobuf-3.21.12/debian/patches/CVE-2024-7254-5.patch 
protobuf-3.21.12/debian/patches/CVE-2024-7254-5.patch
--- protobuf-3.21.12/debian/patches/CVE-2024-7254-5.patch       1970-01-01 
02:00:00.000000000 +0200
+++ protobuf-3.21.12/debian/patches/CVE-2024-7254-5.patch       2026-07-02 
22:07:33.000000000 +0300
@@ -0,0 +1,66 @@
+From b5a7cf7cf4b7e39f6b02205e45afe2104a7faf81 Mon Sep 17 00:00:00 2001
+From: Sandy Zhang <[email protected]>
+Date: Wed, 18 Sep 2024 15:25:25 -0400
+Subject: [PATCH 5/5] Remove RecursiveGroup test case which doesn't exist in
+ 25.x pre-Editions
+
+---
+ .../java/com/google/protobuf/LiteTest.java    | 20 -------------------
+ src/google/protobuf/unittest_lite.proto       |  4 ----
+ 2 files changed, 24 deletions(-)
+
+Index: 
protobuf-3.21.12/java/lite/src/test/java/com/google/protobuf/LiteTest.java
+===================================================================
+--- 
protobuf-3.21.12.orig/java/lite/src/test/java/com/google/protobuf/LiteTest.java
++++ protobuf-3.21.12/java/lite/src/test/java/com/google/protobuf/LiteTest.java
+@@ -40,7 +40,6 @@ import com.google.protobuf.UnittestImpor
+ import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
+ import com.google.protobuf.UnittestLite.ForeignEnumLite;
+ import com.google.protobuf.UnittestLite.ForeignMessageLite;
+-import com.google.protobuf.UnittestLite.RecursiveGroup;
+ import com.google.protobuf.UnittestLite.RecursiveMessage;
+ import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+ import com.google.protobuf.UnittestLite.TestAllTypesLite;
+@@ -2612,17 +2611,6 @@ public class LiteTest {
+   }
+ 
+   @Test
+-  public void testParseFromBytes_recursiveKnownGroups() throws Exception {
+-    byte[] data99 = makeRecursiveGroup(99).toByteArray();
+-    byte[] data100 = makeRecursiveGroup(100).toByteArray();
+-
+-    RecursiveGroup unused = RecursiveGroup.parseFrom(data99);
+-    Throwable thrown =
+-        assertThrows(InvalidProtocolBufferException.class, () -> 
RecursiveGroup.parseFrom(data100));
+-    assertThat(thrown).hasMessageThat().contains("Protocol message had too 
many levels of nesting");
+-  }
+-
+-  @Test
+   @SuppressWarnings("ProtoParseFromByteString")
+   public void testMaliciousSGroupTagsWithMapField_fromByteArray() throws 
Exception {
+     ByteString byteString = generateNestingGroups(102);
+@@ -3040,12 +3028,4 @@ public class LiteTest {
+       return 
RecursiveMessage.newBuilder().setRecurse(makeRecursiveMessage(num - 1)).build();
+     }
+   }
+-
+-  private static RecursiveGroup makeRecursiveGroup(int num) {
+-    if (num == 0) {
+-      return RecursiveGroup.getDefaultInstance();
+-    } else {
+-      return RecursiveGroup.newBuilder().setRecurse(makeRecursiveGroup(num - 
1)).build();
+-    }
+-  }
+ }
+Index: protobuf-3.21.12/src/google/protobuf/unittest_lite.proto
+===================================================================
+--- protobuf-3.21.12.orig/src/google/protobuf/unittest_lite.proto
++++ protobuf-3.21.12/src/google/protobuf/unittest_lite.proto
+@@ -518,7 +518,3 @@ message RecursiveMessage {
+   optional RecursiveMessage recurse = 1;
+   optional bytes payload = 2;
+ }
+-
+-message RecursiveGroup {
+-  optional RecursiveGroup recurse = 1 [features.message_encoding = DELIMITED];
+-}
diff -Nru protobuf-3.21.12/debian/patches/CVE-2024-7254.patch 
protobuf-3.21.12/debian/patches/CVE-2024-7254.patch
--- protobuf-3.21.12/debian/patches/CVE-2024-7254.patch 2025-04-29 
22:27:02.000000000 +0300
+++ protobuf-3.21.12/debian/patches/CVE-2024-7254.patch 1970-01-01 
02:00:00.000000000 +0200
@@ -1,143 +0,0 @@
-From cc8b3483a5584b3301e3d43d17eb59704857ffaa Mon Sep 17 00:00:00 2001
-From: Protobuf Team Bot <[email protected]>
-Date: Thu, 18 Jul 2024 07:41:01 -0700
-Subject: [PATCH] Internal change
-
-PiperOrigin-RevId: 653615736
----
- .../core/src/main/java/com/google/protobuf/ArrayDecoders.java | 3 +--
- .../com/google/protobuf/InvalidProtocolBufferException.java   | 2 +-
- .../core/src/main/java/com/google/protobuf/MessageSchema.java | 3 +++
- .../src/main/java/com/google/protobuf/MessageSetSchema.java   | 1 +
- .../src/main/java/com/google/protobuf/UnknownFieldSchema.java | 3 +--
- java/lite/src/test/java/com/google/protobuf/LiteTest.java     | 3 +++
- src/google/protobuf/unittest_lite.proto                       | 4 ++++
- 7 files changed, 14 insertions(+), 5 deletions(-)
-
-diff --git a/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java 
b/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
-index f3241de5095c0..9bf14396263a3 100644
---- a/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
-+++ b/java/core/src/main/java/com/google/protobuf/ArrayDecoders.java
-@@ -47,8 +47,7 @@
- @CheckReturnValue
- final class ArrayDecoders {
- 
--  private ArrayDecoders() {
--  }
-+  private ArrayDecoders() {}
- 
-   /**
-    * A helper used to return multiple values in a Java function. Java doesn't 
natively support
-diff --git 
a/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
 
b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
-index 5d10e48884c1a..dbcb9e899dbee 100644
---- 
a/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
-+++ 
b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
-@@ -155,7 +155,7 @@ public InvalidWireTypeException(String description) {
-   static InvalidProtocolBufferException recursionLimitExceeded() {
-     return new InvalidProtocolBufferException(
-         "Protocol message had too many levels of nesting.  May be malicious.  
"
--            + "Use CodedInputStream.setRecursionLimit() to increase the depth 
limit.");
-+            + "Use setRecursionLimit() to increase the recursion depth 
limit.");
-   }
- 
-   static InvalidProtocolBufferException sizeLimitExceeded() {
-diff --git a/java/core/src/main/java/com/google/protobuf/MessageSchema.java 
b/java/core/src/main/java/com/google/protobuf/MessageSchema.java
-index de3890f7023aa..f8f79fcdf8b4c 100644
---- a/java/core/src/main/java/com/google/protobuf/MessageSchema.java
-+++ b/java/core/src/main/java/com/google/protobuf/MessageSchema.java
-@@ -3946,6 +3946,7 @@ private <UT, UB, ET extends FieldDescriptorLite<ET>> 
void mergeFromHelper(
-               unknownFields = 
unknownFieldSchema.getBuilderFromMessage(message);
-             }
-             // Unknown field.
-+
-             if (unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader)) {
-               continue;
-             }
-@@ -4321,6 +4322,7 @@ private <UT, UB, ET extends FieldDescriptorLite<ET>> 
void mergeFromHelper(
-               if (unknownFields == null) {
-                 unknownFields = 
unknownFieldSchema.getBuilderFromMessage(message);
-               }
-+
-               if (!unknownFieldSchema.mergeOneFieldFrom(unknownFields, 
reader)) {
-                 return;
-               }
-@@ -4337,6 +4339,7 @@ private <UT, UB, ET extends FieldDescriptorLite<ET>> 
void mergeFromHelper(
-             if (unknownFields == null) {
-               unknownFields = 
unknownFieldSchema.getBuilderFromMessage(message);
-             }
-+
-             if (!unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader)) 
{
-               return;
-             }
-diff --git a/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java 
b/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
-index eec3acd35ca79..a17037e8efd4e 100644
---- a/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
-+++ b/java/core/src/main/java/com/google/protobuf/MessageSetSchema.java
-@@ -301,6 +301,7 @@ boolean parseMessageSetItemOrUnknownField(
-               reader, extension, extensionRegistry, extensions);
-           return true;
-         } else {
-+
-           return unknownFieldSchema.mergeOneFieldFrom(unknownFields, reader);
-         }
-       } else {
-diff --git 
a/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java 
b/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java
-index c4ec645bf7fc8..a43bc2a9472d3 100644
---- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java
-+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSchema.java
-@@ -78,7 +78,6 @@ abstract class UnknownFieldSchema<T, B> {
-   /** Marks unknown fields as immutable. */
-   abstract void makeImmutable(Object message);
- 
--  /** Merges one field into the unknown fields. */
-   final boolean mergeOneFieldFrom(B unknownFields, Reader reader) throws 
IOException {
-     int tag = reader.getTag();
-     int fieldNumber = WireFormat.getTagFieldNumber(tag);
-@@ -111,7 +110,7 @@ final boolean mergeOneFieldFrom(B unknownFields, Reader 
reader) throws IOExcepti
-     }
-   }
- 
--  final void mergeFrom(B unknownFields, Reader reader) throws IOException {
-+  private final void mergeFrom(B unknownFields, Reader reader) throws 
IOException {
-     while (true) {
-       if (reader.getFieldNumber() == Reader.READ_DONE
-           || !mergeOneFieldFrom(unknownFields, reader)) {
-diff --git a/java/lite/src/test/java/com/google/protobuf/LiteTest.java 
b/java/lite/src/test/java/com/google/protobuf/LiteTest.java
-index 0c7b8b535b18d..411bc63f087fd 100644
---- a/java/lite/src/test/java/com/google/protobuf/LiteTest.java
-+++ b/java/lite/src/test/java/com/google/protobuf/LiteTest.java
-@@ -33,12 +33,14 @@
- import static com.google.common.truth.Truth.assertThat;
- import static com.google.common.truth.Truth.assertWithMessage;
- import static java.util.Collections.singletonList;
-+import static org.junit.Assert.assertThrows;
- 
- import com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
- import com.google.protobuf.UnittestImportLite.ImportEnumLite;
- import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite;
- import com.google.protobuf.UnittestLite.ForeignEnumLite;
- import com.google.protobuf.UnittestLite.ForeignMessageLite;
-+import com.google.protobuf.UnittestLite.RecursiveGroup;
- import com.google.protobuf.UnittestLite.RecursiveMessage;
- import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
- import com.google.protobuf.UnittestLite.TestAllTypesLite;
-@@ -72,6 +74,7 @@
- import java.util.Arrays;
- import java.util.Iterator;
- import java.util.List;
-+import java.util.concurrent.atomic.AtomicBoolean;
- import org.junit.Before;
- import org.junit.Test;
- import org.junit.runner.RunWith;
-diff --git a/src/google/protobuf/unittest_lite.proto 
b/src/google/protobuf/unittest_lite.proto
-index b3fcfa431c00a..4bc78c4de6a80 100644
---- a/src/google/protobuf/unittest_lite.proto
-+++ b/src/google/protobuf/unittest_lite.proto
-@@ -518,3 +518,7 @@ message RecursiveMessage {
-   optional RecursiveMessage recurse = 1;
-   optional bytes payload = 2;
- }
-+
-+message RecursiveGroup {
-+  optional RecursiveGroup recurse = 1;
-+}
diff -Nru protobuf-3.21.12/debian/patches/CVE-2025-4565-1.patch 
protobuf-3.21.12/debian/patches/CVE-2025-4565-1.patch
--- protobuf-3.21.12/debian/patches/CVE-2025-4565-1.patch       1970-01-01 
02:00:00.000000000 +0200
+++ protobuf-3.21.12/debian/patches/CVE-2025-4565-1.patch       2026-07-02 
22:07:33.000000000 +0300
@@ -0,0 +1,117 @@
+From f69ea1cc48191534c3450a1053f3741250274eca Mon Sep 17 00:00:00 2001
+From: Mike Kruskal <[email protected]>
+Date: Mon, 9 Dec 2024 20:04:43 -0800
+Subject: [PATCH] Make Pure Python reject unmatched end-group tag in unknown
+ fields
+
+This brings it into conformance with our spec and other languages.
+
+PiperOrigin-RevId: 704518974
+
+Origin: upstream, 
https://github.com/protocolbuffers/protobuf/commit/f69ea1cc48191534c3450a1053f3741250274eca.patch
+Bug: https://www.cve.org/CVERecord?id=CVE-2025-4565
+Bug-Debian: https://bugs.debian.org/1108057
+---
+ conformance/failure_list_python.txt           |  3 -
+ python/google/protobuf/internal/decoder.py    | 14 ++++-
+ .../google/protobuf/internal/decoder_test.py  | 56 ++++++++++++++++++-
+ .../google/protobuf/internal/message_test.py  | 31 ++++++----
+ .../protobuf/internal/python_message.py       |  3 +-
+ python/google/protobuf/unknown_fields.py      |  3 +-
+ 6 files changed, 90 insertions(+), 20 deletions(-)
+
+diff --git a/python/google/protobuf/internal/decoder.py 
b/python/google/protobuf/internal/decoder.py
+index dcde1d942..e26770e1d 100755
+--- a/python/google/protobuf/internal/decoder.py
++++ b/python/google/protobuf/internal/decoder.py
+@@ -976,14 +976,16 @@ def _DecodeUnknownFieldSet(buffer, pos, end_pos=None):
+     field_number, wire_type = wire_format.UnpackTag(tag)
+     if wire_type == wire_format.WIRETYPE_END_GROUP:
+       break
+-    (data, pos) = _DecodeUnknownField(buffer, pos, wire_type)
++    (data, pos) = _DecodeUnknownField(
++        buffer, pos, end_pos, field_number, wire_type
++    )
+     # pylint: disable=protected-access
+     unknown_field_set._add(field_number, wire_type, data)
+ 
+   return (unknown_field_set, pos)
+ 
+ 
+-def _DecodeUnknownField(buffer, pos, wire_type):
++def _DecodeUnknownField(buffer, pos, end_pos, field_number, wire_type):
+   """Decode a unknown field.  Returns the UnknownField and new position."""
+ 
+   if wire_type == wire_format.WIRETYPE_VARINT:
+@@ -997,7 +999,13 @@ def _DecodeUnknownField(buffer, pos, wire_type):
+     data = buffer[pos:pos+size].tobytes()
+     pos += size
+   elif wire_type == wire_format.WIRETYPE_START_GROUP:
+-    (data, pos) = _DecodeUnknownFieldSet(buffer, pos)
++    end_tag_bytes = encoder.TagBytes(
++        field_number, wire_format.WIRETYPE_END_GROUP
++    )
++    data, pos = _DecodeUnknownFieldSet(buffer, pos, end_pos)
++    # Check end tag.
++    if buffer[pos - len(end_tag_bytes) : pos] != end_tag_bytes:
++      raise _DecodeError('Missing group end tag.')
+   elif wire_type == wire_format.WIRETYPE_END_GROUP:
+     return (0, -1)
+   else:
+diff --git a/python/google/protobuf/internal/message_test.py 
b/python/google/protobuf/internal/message_test.py
+index f1541f14b..7212639db 100755
+--- a/python/google/protobuf/internal/message_test.py
++++ b/python/google/protobuf/internal/message_test.py
+@@ -122,6 +122,8 @@ class MessageTest(unittest.TestCase):
+     msg = message_module.TestAllTypes()
+     self.assertRaises(TypeError, msg.FromString, 0)
+     self.assertRaises(Exception, msg.FromString, '0')
++
++    # Unexpected end group tag.
+     # TODO(jieluo): Fix cpp extension to raise error instead of warning.
+     # b/27494216
+     end_tag = encoder.TagBytes(1, 4)
+@@ -133,6 +133,15 @@ class MessageTest(unittest.TestCase):
+         # Only pure-Python has an error message this specific.
+         self.assertEqual('Unexpected end-group tag.', str(context.exception))
+ 
++    # Unmatched start group tag.
++    start_tag = encoder.TagBytes(2, 3)
++    with self.assertRaises(message.DecodeError):
++      msg.FromString(start_tag)
++
++    # Mismatched end group tag.
++    with self.assertRaises(message.DecodeError):
++      msg.FromString(start_tag + end_tag)
++
+     # Field number 0 is illegal.
+     self.assertRaises(message.DecodeError, msg.FromString, b'\3\4')
+ 
+diff --git a/python/google/protobuf/internal/python_message.py 
b/python/google/protobuf/internal/python_message.py
+index 1f9016880..22d02c4d6 100755
+--- a/python/google/protobuf/internal/python_message.py
++++ b/python/google/protobuf/internal/python_message.py
+@@ -1179,7 +1179,8 @@ def _AddMergeFromStringMethod(message_de
+         # TODO(jieluo): remove old_pos.
+         old_pos = new_pos
+         (data, new_pos) = decoder._DecodeUnknownField(
+-            buffer, new_pos, wire_type)  # pylint: disable=protected-access
++            buffer, new_pos, end, field_number, wire_type
++        )  # pylint: disable=protected-access
+         if new_pos == -1:
+           return pos
+         # pylint: disable=protected-access
+diff --git a/python/google/protobuf/unknown_fields.py 
b/python/google/protobuf/unknown_fields.py
+index 9b1e54932..1a4537e3f 100644
+--- a/python/google/protobuf/unknown_fields.py
++++ b/python/google/protobuf/unknown_fields.py
+@@ -101,7 +101,8 @@ else:
+           if field_number == 0:
+             raise RuntimeError('Field number 0 is illegal.')
+           (data, _) = decoder._DecodeUnknownField(
+-              memoryview(buffer), 0, wire_type)
++              memoryview(buffer), 0, len(buffer), field_number, wire_type
++          )
+           InternalAdd(field_number, wire_type, data)
+ 
+     def __getitem__(self, index):
diff -Nru protobuf-3.21.12/debian/patches/CVE-2025-4565-2.patch 
protobuf-3.21.12/debian/patches/CVE-2025-4565-2.patch
--- protobuf-3.21.12/debian/patches/CVE-2025-4565-2.patch       1970-01-01 
02:00:00.000000000 +0200
+++ protobuf-3.21.12/debian/patches/CVE-2025-4565-2.patch       2026-07-02 
22:07:33.000000000 +0300
@@ -0,0 +1,395 @@
+From a6fa5799ff0153e4f0f6f1d8263d6b492ac129e0 Mon Sep 17 00:00:00 2001
+From: Protobuf Team Bot <[email protected]>
+Date: Tue, 4 Mar 2025 13:16:32 -0800
+Subject: [PATCH] Internal pure python fixes
+
+PiperOrigin-RevId: 733441339
+
+Origin: upstream, 
https://github.com/protocolbuffers/protobuf/commit/a6fa5799ff0153e4f0f6f1d8263d6b492ac129e0.patch
+Bug: https://www.cve.org/CVERecord?id=CVE-2025-4565
+Bug-Debian: https://bugs.debian.org/1108057
+---
+ python/google/protobuf/internal/decoder.py    | 98 ++++++++++++++-----
+ .../google/protobuf/internal/message_test.py  |  1 +
+ .../protobuf/internal/python_message.py       |  7 +-
+ .../protobuf/internal/self_recursive.proto    |  9 +-
+ 4 files changed, 86 insertions(+), 29 deletions(-)
+
+diff --git a/python/google/protobuf/internal/decoder.py 
b/python/google/protobuf/internal/decoder.py
+index 91a4c7541e3dc..e2a3de17089ab 100755
+--- a/python/google/protobuf/internal/decoder.py
++++ b/python/google/protobuf/internal/decoder.py
+@@ -195,7 +195,10 @@ def SpecificDecoder(field_number, is_repeated, is_packed, 
key, new_default,
+                       clear_if_default=False):
+     if is_packed:
+       local_DecodeVarint = _DecodeVarint
+-      def DecodePackedField(buffer, pos, end, message, field_dict):
++      def DecodePackedField(
++          buffer, pos, end, message, field_dict, current_depth=0
++      ):
++        del current_depth  # unused
+         value = field_dict.get(key)
+         if value is None:
+           value = field_dict.setdefault(key, new_default(message))
+@@ -210,11 +213,15 @@ def DecodePackedField(buffer, pos, end, message, 
field_dict):
+           del value[-1]   # Discard corrupt value.
+           raise _DecodeError('Packed element was truncated.')
+         return pos
++
+       return DecodePackedField
+     elif is_repeated:
+       tag_bytes = encoder.TagBytes(field_number, wire_type)
+       tag_len = len(tag_bytes)
+-      def DecodeRepeatedField(buffer, pos, end, message, field_dict):
++      def DecodeRepeatedField(
++          buffer, pos, end, message, field_dict, current_depth=0
++      ):
++        del current_depth  # unused
+         value = field_dict.get(key)
+         if value is None:
+           value = field_dict.setdefault(key, new_default(message))
+@@ -229,9 +236,12 @@ def DecodeRepeatedField(buffer, pos, end, message, 
field_dict):
+             if new_pos > end:
+               raise _DecodeError('Truncated message.')
+             return new_pos
++
+       return DecodeRepeatedField
+     else:
+-      def DecodeField(buffer, pos, end, message, field_dict):
++
++      def DecodeField(buffer, pos, end, message, field_dict, current_depth=0):
++        del current_depth  # unused
+         (new_value, pos) = decode_value(buffer, pos)
+         if pos > end:
+           raise _DecodeError('Truncated message.')
+@@ -240,6 +250,7 @@ def DecodeField(buffer, pos, end, message, field_dict):
+         else:
+           field_dict[key] = new_value
+         return pos
++
+       return DecodeField
+ 
+   return SpecificDecoder
+@@ -375,7 +386,9 @@ def EnumDecoder(field_number, is_repeated, is_packed, key, 
new_default,
+   enum_type = key.enum_type
+   if is_packed:
+     local_DecodeVarint = _DecodeVarint
+-    def DecodePackedField(buffer, pos, end, message, field_dict):
++    def DecodePackedField(
++        buffer, pos, end, message, field_dict, current_depth=0
++    ):
+       """Decode serialized packed enum to its value and a new position.
+ 
+       Args:
+@@ -388,6 +401,7 @@ def DecodePackedField(buffer, pos, end, message, 
field_dict):
+       Returns:
+         int, new position in serialized data.
+       """
++      del current_depth  # unused
+       value = field_dict.get(key)
+       if value is None:
+         value = field_dict.setdefault(key, new_default(message))
+@@ -424,11 +438,14 @@ def DecodePackedField(buffer, pos, end, message, 
field_dict):
+           # pylint: enable=protected-access
+         raise _DecodeError('Packed element was truncated.')
+       return pos
++
+     return DecodePackedField
+   elif is_repeated:
+     tag_bytes = encoder.TagBytes(field_number, wire_format.WIRETYPE_VARINT)
+     tag_len = len(tag_bytes)
+-    def DecodeRepeatedField(buffer, pos, end, message, field_dict):
++    def DecodeRepeatedField(
++        buffer, pos, end, message, field_dict, current_depth=0
++    ):
+       """Decode serialized repeated enum to its value and a new position.
+ 
+       Args:
+@@ -441,6 +458,7 @@ def DecodeRepeatedField(buffer, pos, end, message, 
field_dict):
+       Returns:
+         int, new position in serialized data.
+       """
++      del current_depth  # unused
+       value = field_dict.get(key)
+       if value is None:
+         value = field_dict.setdefault(key, new_default(message))
+@@ -467,9 +485,11 @@ def DecodeRepeatedField(buffer, pos, end, message, 
field_dict):
+           if new_pos > end:
+             raise _DecodeError('Truncated message.')
+           return new_pos
++
+     return DecodeRepeatedField
+   else:
+-    def DecodeField(buffer, pos, end, message, field_dict):
++
++    def DecodeField(buffer, pos, end, message, field_dict, current_depth=0):
+       """Decode serialized repeated enum to its value and a new position.
+ 
+       Args:
+@@ -482,6 +502,7 @@ def DecodeField(buffer, pos, end, message, field_dict):
+       Returns:
+         int, new position in serialized data.
+       """
++      del current_depth  # unused
+       value_start_pos = pos
+       (enum_value, pos) = _DecodeSignedVarint32(buffer, pos)
+       if pos > end:
+@@ -505,6 +505,7 @@ def EnumDecoder(field_number, is_repeate
+             field_number, wire_format.WIRETYPE_VARINT, enum_value)
+         # pylint: enable=protected-access
+       return pos
++
+     return DecodeField
+ 
+ 
+@@ -563,7 +585,10 @@ def _ConvertToUnicode(memview):
+     tag_bytes = encoder.TagBytes(field_number,
+                                  wire_format.WIRETYPE_LENGTH_DELIMITED)
+     tag_len = len(tag_bytes)
+-    def DecodeRepeatedField(buffer, pos, end, message, field_dict):
++    def DecodeRepeatedField(
++        buffer, pos, end, message, field_dict, current_depth=0
++    ):
++      del current_depth  # unused
+       value = field_dict.get(key)
+       if value is None:
+         value = field_dict.setdefault(key, new_default(message))
+@@ -578,9 +603,12 @@ def DecodeRepeatedField(buffer, pos, end, message, 
field_dict):
+         if buffer[new_pos:pos] != tag_bytes or new_pos == end:
+           # Prediction failed.  Return.
+           return new_pos
++
+     return DecodeRepeatedField
+   else:
+-    def DecodeField(buffer, pos, end, message, field_dict):
++
++    def DecodeField(buffer, pos, end, message, field_dict, current_depth=0):
++      del current_depth  # unused
+       (size, pos) = local_DecodeVarint(buffer, pos)
+       new_pos = pos + size
+       if new_pos > end:
+@@ -590,6 +618,7 @@ def DecodeField(buffer, pos, end, message, field_dict):
+       else:
+         field_dict[key] = _ConvertToUnicode(buffer[pos:new_pos])
+       return new_pos
++
+     return DecodeField
+ 
+ 
+@@ -604,7 +633,10 @@ def BytesDecoder(field_number, is_repeated, is_packed, 
key, new_default,
+     tag_bytes = encoder.TagBytes(field_number,
+                                  wire_format.WIRETYPE_LENGTH_DELIMITED)
+     tag_len = len(tag_bytes)
+-    def DecodeRepeatedField(buffer, pos, end, message, field_dict):
++    def DecodeRepeatedField(
++        buffer, pos, end, message, field_dict, current_depth=0
++    ):
++      del current_depth  # unused
+       value = field_dict.get(key)
+       if value is None:
+         value = field_dict.setdefault(key, new_default(message))
+@@ -619,9 +651,12 @@ def DecodeRepeatedField(buffer, pos, end, message, 
field_dict):
+         if buffer[new_pos:pos] != tag_bytes or new_pos == end:
+           # Prediction failed.  Return.
+           return new_pos
++
+     return DecodeRepeatedField
+   else:
+-    def DecodeField(buffer, pos, end, message, field_dict):
++
++    def DecodeField(buffer, pos, end, message, field_dict, current_depth=0):
++      del current_depth  # unused
+       (size, pos) = local_DecodeVarint(buffer, pos)
+       new_pos = pos + size
+       if new_pos > end:
+@@ -631,6 +666,7 @@ def DecodeField(buffer, pos, end, message, field_dict):
+       else:
+         field_dict[key] = buffer[pos:new_pos].tobytes()
+       return new_pos
++
+     return DecodeField
+ 
+ 
+@@ -646,7 +682,9 @@ def GroupDecoder(field_number, is_repeated, is_packed, 
key, new_default):
+     tag_bytes = encoder.TagBytes(field_number,
+                                  wire_format.WIRETYPE_START_GROUP)
+     tag_len = len(tag_bytes)
+-    def DecodeRepeatedField(buffer, pos, end, message, field_dict):
++    def DecodeRepeatedField(
++        buffer, pos, end, message, field_dict, current_depth=0
++    ):
+       value = field_dict.get(key)
+       if value is None:
+         value = field_dict.setdefault(key, new_default(message))
+@@ -655,7 +693,7 @@ def DecodeRepeatedField(buffer, pos, end, message, 
field_dict):
+         if value is None:
+           value = field_dict.setdefault(key, new_default(message))
+         # Read sub-message.
+-        pos = value.add()._InternalParse(buffer, pos, end)
++        pos = value.add()._InternalParse(buffer, pos, end, current_depth)
+         # Read end tag.
+         new_pos = pos+end_tag_len
+         if buffer[pos:new_pos] != end_tag_bytes or new_pos > end:
+@@ -665,19 +703,22 @@ def DecodeRepeatedField(buffer, pos, end, message, 
field_dict):
+         if buffer[new_pos:pos] != tag_bytes or new_pos == end:
+           # Prediction failed.  Return.
+           return new_pos
++
+     return DecodeRepeatedField
+   else:
+-    def DecodeField(buffer, pos, end, message, field_dict):
++
++    def DecodeField(buffer, pos, end, message, field_dict, current_depth=0):
+       value = field_dict.get(key)
+       if value is None:
+         value = field_dict.setdefault(key, new_default(message))
+       # Read sub-message.
+-      pos = value._InternalParse(buffer, pos, end)
++      pos = value._InternalParse(buffer, pos, end, current_depth)
+       # Read end tag.
+       new_pos = pos+end_tag_len
+       if buffer[pos:new_pos] != end_tag_bytes or new_pos > end:
+         raise _DecodeError('Missing group end tag.')
+       return new_pos
++
+     return DecodeField
+ 
+ 
+@@ -691,7 +732,9 @@ def MessageDecoder(field_number, is_repeated, is_packed, 
key, new_default):
+     tag_bytes = encoder.TagBytes(field_number,
+                                  wire_format.WIRETYPE_LENGTH_DELIMITED)
+     tag_len = len(tag_bytes)
+-    def DecodeRepeatedField(buffer, pos, end, message, field_dict):
++    def DecodeRepeatedField(
++        buffer, pos, end, message, field_dict, current_depth=0
++    ):
+       value = field_dict.get(key)
+       if value is None:
+         value = field_dict.setdefault(key, new_default(message))
+@@ -702,7 +745,10 @@ def DecodeRepeatedField(buffer, pos, end, message, 
field_dict):
+         if new_pos > end:
+           raise _DecodeError('Truncated message.')
+         # Read sub-message.
+-        if value.add()._InternalParse(buffer, pos, new_pos) != new_pos:
++        if (
++            value.add()._InternalParse(buffer, pos, new_pos, current_depth)
++            != new_pos
++        ):
+           # The only reason _InternalParse would return early is if it
+           # encountered an end-group tag.
+           raise _DecodeError('Unexpected end-group tag.')
+@@ -711,9 +757,11 @@ def DecodeRepeatedField(buffer, pos, end, message, 
field_dict):
+         if buffer[new_pos:pos] != tag_bytes or new_pos == end:
+           # Prediction failed.  Return.
+           return new_pos
++
+     return DecodeRepeatedField
+   else:
+-    def DecodeField(buffer, pos, end, message, field_dict):
++
++    def DecodeField(buffer, pos, end, message, field_dict, current_depth=0):
+       value = field_dict.get(key)
+       if value is None:
+         value = field_dict.setdefault(key, new_default(message))
+@@ -723,11 +771,12 @@ def DecodeField(buffer, pos, end, message, field_dict):
+       if new_pos > end:
+         raise _DecodeError('Truncated message.')
+       # Read sub-message.
+-      if value._InternalParse(buffer, pos, new_pos) != new_pos:
++      if value._InternalParse(buffer, pos, new_pos, current_depth) != new_pos:
+         # The only reason _InternalParse would return early is if it 
encountered
+         # an end-group tag.
+         raise _DecodeError('Unexpected end-group tag.')
+       return new_pos
++
+     return DecodeField
+ 
+ 
+@@ -883,7 +932,8 @@ def MapDecoder(field_descriptor, new_default, 
is_message_map):
+   # Can't read _concrete_class yet; might not be initialized.
+   message_type = field_descriptor.message_type
+ 
+-  def DecodeMap(buffer, pos, end, message, field_dict):
++  def DecodeMap(buffer, pos, end, message, field_dict, current_depth=0):
++    del current_depth  # Unused.
+     submsg = message_type._concrete_class()
+     value = field_dict.get(key)
+     if value is None:
+@@ -966,7 +966,7 @@ def _SkipGroup(buffer, pos, end):
+     pos = new_pos
+ 
+ 
+-def _DecodeUnknownFieldSet(buffer, pos, end_pos=None):
++def _DecodeUnknownFieldSet(buffer, pos, end_pos=None, current_depth=0):
+   """Decode UnknownFieldSet.  Returns the UnknownFieldSet and new position."""
+ 
+   unknown_field_set = containers.UnknownFieldSet()
+@@ -977,7 +1027,7 @@ def _DecodeUnknownFieldSet(buffer, pos, end_pos=None):
+     if wire_type == wire_format.WIRETYPE_END_GROUP:
+       break
+     (data, pos) = _DecodeUnknownField(
+-        buffer, pos, end_pos, field_number, wire_type
++        buffer, pos, end_pos, field_number, wire_type, current_depth
+     )
+     # pylint: disable=protected-access
+     unknown_field_set._add(field_number, wire_type, data)
+@@ -985,7 +1035,9 @@ def _DecodeUnknownFieldSet(buffer, pos, end_pos=None):
+   return (unknown_field_set, pos)
+ 
+ 
+-def _DecodeUnknownField(buffer, pos, end_pos, field_number, wire_type):
++def _DecodeUnknownField(
++    buffer, pos, end_pos, field_number, wire_type, current_depth=0
++):
+   """Decode a unknown field.  Returns the UnknownField and new position."""
+ 
+   if wire_type == wire_format.WIRETYPE_VARINT:
+@@ -1002,7 +1054,7 @@ def _DecodeUnknownField(buffer, pos, end_pos, 
field_number, wire_type):
+     end_tag_bytes = encoder.TagBytes(
+         field_number, wire_format.WIRETYPE_END_GROUP
+     )
+-    data, pos = _DecodeUnknownFieldSet(buffer, pos, end_pos)
++    data, pos = _DecodeUnknownFieldSet(buffer, pos, end_pos, current_depth)
+     # Check end tag.
+     if buffer[pos - len(end_tag_bytes) : pos] != end_tag_bytes:
+       raise _DecodeError('Missing group end tag.')
+diff --git a/python/google/protobuf/internal/message_test.py 
b/python/google/protobuf/internal/message_test.py
+index f8382085b9a00..d9fdf874a7052 100755
+--- a/python/google/protobuf/internal/message_test.py
++++ b/python/google/protobuf/internal/message_test.py
+@@ -60,6 +60,7 @@ from google.protobuf import unittest_pb2
+ from google.protobuf import unittest_proto3_arena_pb2
+ from google.protobuf import descriptor
+ from google.protobuf.internal import api_implementation
++from google.protobuf.internal import decoder
+ from google.protobuf.internal import encoder
+ from google.protobuf.internal import more_extensions_pb2
+ from google.protobuf.internal import packed_field_test_pb2
+diff --git a/python/google/protobuf/internal/python_message.py 
b/python/google/protobuf/internal/python_message.py
+index 23ac28e36d2e0..8cc517c07878d 100755
+--- a/python/google/protobuf/internal/python_message.py
++++ b/python/google/protobuf/internal/python_message.py
+@@ -1141,7 +1141,7 @@ def _AddMergeFromStringMethod(message_de
+   local_SkipField = decoder.SkipField
+   decoders_by_tag = cls._decoders_by_tag
+ 
+-  def InternalParse(self, buffer, pos, end):
++  def InternalParse(self, buffer, pos, end, current_depth=0):
+     """Create a message from serialized bytes.
+ 
+     Args:
+@@ -1193,10 +1193,13 @@ def _AddMergeFromStringMethod(message_de
+             (tag_bytes, buffer[old_pos:new_pos].tobytes()))
+         pos = new_pos
+       else:
+-        pos = field_decoder(buffer, new_pos, end, self, field_dict)
++        pos = field_decoder(
++            buffer, new_pos, end, self, field_dict, current_depth
++        )
+         if field_desc:
+           self._UpdateOneofState(field_desc)
+     return pos
++
+   cls._InternalParse = InternalParse
+ 
+ 
diff -Nru protobuf-3.21.12/debian/patches/CVE-2025-4565-3.patch 
protobuf-3.21.12/debian/patches/CVE-2025-4565-3.patch
--- protobuf-3.21.12/debian/patches/CVE-2025-4565-3.patch       1970-01-01 
02:00:00.000000000 +0200
+++ protobuf-3.21.12/debian/patches/CVE-2025-4565-3.patch       2026-07-02 
22:07:33.000000000 +0300
@@ -0,0 +1,207 @@
+From 17838beda2943d08b8a9d4df5b68f5f04f26d901 Mon Sep 17 00:00:00 2001
+From: Protobuf Team Bot <[email protected]>
+Date: Tue, 13 May 2025 14:42:18 -0700
+Subject: [PATCH] Add recursion depth limits to pure python
+
+PiperOrigin-RevId: 758382549
+
+Origin: upstream, 
https://github.com/protocolbuffers/protobuf/commit/17838beda2943d08b8a9d4df5b68f5f04f26d901.patch
+Bug: https://www.cve.org/CVERecord?id=CVE-2025-4565
+Bug-Debian: https://bugs.debian.org/1108057
+---
+ python/google/protobuf/internal/decoder.py    | 31 ++++++++
+ .../google/protobuf/internal/message_test.py  | 76 ++++++++++++++-----
+ .../protobuf/internal/self_recursive.proto    |  1 +
+ 4 files changed, 102 insertions(+), 19 deletions(-)
+
+diff --git a/python/google/protobuf/internal/decoder.py 
b/python/google/protobuf/internal/decoder.py
+index e2a3de17089ab..dbf848bf31083 100755
+--- a/python/google/protobuf/internal/decoder.py
++++ b/python/google/protobuf/internal/decoder.py
+@@ -693,7 +693,13 @@ def DecodeRepeatedField(
+         if value is None:
+           value = field_dict.setdefault(key, new_default(message))
+         # Read sub-message.
++        current_depth += 1
++        if current_depth > _recursion_limit:
++          raise _DecodeError(
++              'Error parsing message: too many levels of nesting.'
++          )
+         pos = value.add()._InternalParse(buffer, pos, end, current_depth)
++        current_depth -= 1
+         # Read end tag.
+         new_pos = pos+end_tag_len
+         if buffer[pos:new_pos] != end_tag_bytes or new_pos > end:
+@@ -712,7 +718,11 @@ def DecodeField(buffer, pos, end, message, field_dict, 
current_depth=0):
+       if value is None:
+         value = field_dict.setdefault(key, new_default(message))
+       # Read sub-message.
++      current_depth += 1
++      if current_depth > _recursion_limit:
++        raise _DecodeError('Error parsing message: too many levels of 
nesting.')
+       pos = value._InternalParse(buffer, pos, end, current_depth)
++      current_depth -= 1
+       # Read end tag.
+       new_pos = pos+end_tag_len
+       if buffer[pos:new_pos] != end_tag_bytes or new_pos > end:
+@@ -745,6 +755,11 @@ def DecodeRepeatedField(
+         if new_pos > end:
+           raise _DecodeError('Truncated message.')
+         # Read sub-message.
++        current_depth += 1
++        if current_depth > _recursion_limit:
++          raise _DecodeError(
++              'Error parsing message: too many levels of nesting.'
++          )
+         if (
+             value.add()._InternalParse(buffer, pos, new_pos, current_depth)
+             != new_pos
+@@ -752,6 +767,7 @@ def DecodeRepeatedField(
+           # The only reason _InternalParse would return early is if it
+           # encountered an end-group tag.
+           raise _DecodeError('Unexpected end-group tag.')
++        current_depth -= 1
+         # Predict that the next tag is another copy of the same repeated 
field.
+         pos = new_pos + tag_len
+         if buffer[new_pos:pos] != tag_bytes or new_pos == end:
+@@ -771,10 +787,14 @@ def DecodeField(buffer, pos, end, message, field_dict, 
current_depth=0):
+       if new_pos > end:
+         raise _DecodeError('Truncated message.')
+       # Read sub-message.
++      current_depth += 1
++      if current_depth > _recursion_limit:
++        raise _DecodeError('Error parsing message: too many levels of 
nesting.')
+       if value._InternalParse(buffer, pos, new_pos, current_depth) != new_pos:
+         # The only reason _InternalParse would return early is if it 
encountered
+         # an end-group tag.
+         raise _DecodeError('Unexpected end-group tag.')
++      current_depth -= 1
+       return new_pos
+ 
+     return DecodeField
+@@ -1054,7 +1054,11 @@ def _DecodeUnknownField(
+     end_tag_bytes = encoder.TagBytes(
+         field_number, wire_format.WIRETYPE_END_GROUP
+     )
++    current_depth += 1
++    if current_depth >= _recursion_limit:
++      raise _DecodeError('Error parsing message: too many levels of nesting.')
+     data, pos = _DecodeUnknownFieldSet(buffer, pos, end_pos, current_depth)
++    current_depth -= 1
+     # Check end tag.
+     if buffer[pos - len(end_tag_bytes) : pos] != end_tag_bytes:
+       raise _DecodeError('Missing group end tag.')
+@@ -1086,6 +1086,13 @@ def _DecodeFixed32(buffer, pos):
+ 
+   new_pos = pos + 4
+   return (struct.unpack('<I', buffer[pos:new_pos])[0], new_pos)
++DEFAULT_RECURSION_LIMIT = 100
++_recursion_limit = DEFAULT_RECURSION_LIMIT
++
++
++def SetRecursionLimit(new_limit):
++  global _recursion_limit
++  _recursion_limit = new_limit
+ 
+ 
+ def _RaiseInvalidWireType(buffer, pos, end):
+diff --git a/python/google/protobuf/internal/message_test.py 
b/python/google/protobuf/internal/message_test.py
+index d2c066e6035ec..ea0c707009a14 100755
+--- a/python/google/protobuf/internal/message_test.py
++++ b/python/google/protobuf/internal/message_test.py
+@@ -64,6 +64,7 @@ from google.protobuf.internal import dec
+ from google.protobuf.internal import encoder
+ from google.protobuf.internal import more_extensions_pb2
+ from google.protobuf.internal import packed_field_test_pb2
++from google.protobuf.internal import self_recursive_pb2
+ from google.protobuf.internal import test_util
+ from google.protobuf.internal import test_proto3_optional_pb2
+ from google.protobuf.internal import testing_refleaks
+@@ -1268,6 +1268,52 @@ class MessageTest(unittest.TestCase):
+     self.assertEqual(True, m.repeated_bool[0])
+ 
+ 
++@testing_refleaks.TestCase
++class TestRecursiveGroup(unittest.TestCase):
++
++  def _MakeRecursiveGroupMessage(self, n):
++    msg = self_recursive_pb2.SelfRecursive()
++    sub = msg
++    for _ in range(n):
++      sub = sub.sub_group
++    sub.i = 1
++    return msg.SerializeToString()
++
++  def testRecursiveGroups(self):
++    recurse_msg = self_recursive_pb2.SelfRecursive()
++    data = self._MakeRecursiveGroupMessage(100)
++    recurse_msg.ParseFromString(data)
++    self.assertTrue(recurse_msg.HasField('sub_group'))
++
++  def testRecursiveGroupsException(self):
++    if api_implementation.Type() != 'python':
++      api_implementation._c_module.SetAllowOversizeProtos(False)
++    recurse_msg = self_recursive_pb2.SelfRecursive()
++    data = self._MakeRecursiveGroupMessage(300)
++    with self.assertRaises(message.DecodeError) as context:
++      recurse_msg.ParseFromString(data)
++    self.assertIn('Error parsing message', str(context.exception))
++    if api_implementation.Type() == 'python':
++      self.assertIn('too many levels of nesting', str(context.exception))
++
++  def testRecursiveGroupsUnknownFields(self):
++    if api_implementation.Type() != 'python':
++      api_implementation._c_module.SetAllowOversizeProtos(False)
++    test_msg = unittest_pb2.TestAllTypes()
++    data = self._MakeRecursiveGroupMessage(300)  # unknown to test_msg
++    with self.assertRaises(message.DecodeError) as context:
++      test_msg.ParseFromString(data)
++    self.assertIn(
++        'Error parsing message',
++        str(context.exception),
++    )
++    if api_implementation.Type() == 'python':
++      self.assertIn('too many levels of nesting', str(context.exception))
++      decoder.SetRecursionLimit(310)
++      test_msg.ParseFromString(data)
++      decoder.SetRecursionLimit(decoder.DEFAULT_RECURSION_LIMIT)
++
++
+ # Class to test proto2-only features (required, extensions, etc.)
+ @testing_refleaks.TestCase
+ class Proto2Test(unittest.TestCase):
+@@ -2550,8 +2583,6 @@ def testUnpackedFields(self):
+     self.assertEqual(golden_data, message.SerializeToString())
+ 
+ 
[email protected](api_implementation.Type() == 'python',
+-                 'explicit tests of the C++ implementation')
+ @testing_refleaks.TestCase
+ class OversizeProtosTest(unittest.TestCase):
+ 
+@@ -2568,16 +2599,23 @@ def testSucceedOkSizedProto(self):
+     msg.ParseFromString(self.GenerateNestedProto(100))
+ 
+   def testAssertOversizeProto(self):
+-    api_implementation._c_module.SetAllowOversizeProtos(False)
++    if api_implementation.Type() != 'python':
++      api_implementation._c_module.SetAllowOversizeProtos(False)
+     msg = unittest_pb2.TestRecursiveMessage()
+     with self.assertRaises(message.DecodeError) as context:
+       msg.ParseFromString(self.GenerateNestedProto(101))
+     self.assertIn('Error parsing message', str(context.exception))
+ 
+   def testSucceedOversizeProto(self):
+-    api_implementation._c_module.SetAllowOversizeProtos(True)
++
++    if api_implementation.Type() == 'python':
++      decoder.SetRecursionLimit(310)
++    else:
++      api_implementation._c_module.SetAllowOversizeProtos(True)
++
+     msg = unittest_pb2.TestRecursiveMessage()
+     msg.ParseFromString(self.GenerateNestedProto(101))
++    decoder.SetRecursionLimit(decoder.DEFAULT_RECURSION_LIMIT)
+ 
+ 
+ if __name__ == '__main__':
diff -Nru protobuf-3.21.12/debian/patches/series 
protobuf-3.21.12/debian/patches/series
--- protobuf-3.21.12/debian/patches/series      2025-04-29 22:27:02.000000000 
+0300
+++ protobuf-3.21.12/debian/patches/series      2026-07-02 22:28:01.000000000 
+0300
@@ -19,4 +19,14 @@
 test_scope_for_junit.patch
 stop_using_backward_compatibility_timezones.patch
 python3.12.diff
-CVE-2024-7254.patch
+CVE-2024-7254-1.patch
+CVE-2024-7254-2.patch
+CVE-2024-7254-3.patch
+CVE-2024-7254-4.patch
+CVE-2024-7254-5.patch
+CVE-2025-4565-1.patch
+CVE-2025-4565-2.patch
+CVE-2025-4565-3.patch
+0001-Fix-Any-recursion-depth-bypass-in-Python-json_format.patch
+0002-Check-that-readRaw-does-not-accept-negative-length-v.patch
+0003-php-Fix-that-recursion-limit-is-not-enforced.patch

--- End Message ---
--- Begin Message ---
Version: 13.6

This update was released as part of 13.6.

--- End Message ---

Reply via email to