Hi,

[CC'ing explicitly as well Alexandre as having done the last two
uploads]

On Fri, Jan 16, 2026 at 11:50:00PM +0100, Salvatore Bonaccorso wrote:
> Source: pyasn1
> Version: 0.6.1-1
> Severity: important
> Tags: security upstream
> X-Debbugs-Cc: [email protected], Debian Security Team 
> <[email protected]>
> 
> Hi,
> 
> The following vulnerability was published for pyasn1.
> 
> CVE-2026-23490[0]:
> | pyasn1 is a generic ASN.1 library for Python. Prior to 0.6.2, a
> | Denial-of-Service issue has been found that leads to memory
> | exhaustion from malformed RELATIVE-OID with excessive continuation
> | octets. This vulnerability is fixed in 0.6.2.
> 
> 
> If you fix the vulnerability please also make sure to include the
> CVE (Common Vulnerabilities & Exposures) id in your changelog entry.
> 
> For further information see:
> 
> [0] https://security-tracker.debian.org/tracker/CVE-2026-23490
>     https://www.cve.org/CVERecord?id=CVE-2026-23490
> [1] https://github.com/pyasn1/pyasn1/security/advisories/GHSA-63vm-454h-vhhq
> [2] 
> https://github.com/pyasn1/pyasn1/commit/3908f144229eed4df24bd569d16e5991ace44970
> 
> Please adjust the affected versions in the BTS as needed.

Attached the proposed debdiff (not uploaded, neither to delayed yet)
which I would like to use as basis for the trixie-security DSA.

Regards,
Salvatore
diff -Nru pyasn1-0.6.1/debian/changelog pyasn1-0.6.1/debian/changelog
--- pyasn1-0.6.1/debian/changelog       2025-02-13 18:59:57.000000000 +0100
+++ pyasn1-0.6.1/debian/changelog       2026-01-19 07:01:31.000000000 +0100
@@ -1,3 +1,11 @@
+pyasn1 (0.6.1-1.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * Fixed continuation octet limits in OID/RELATIVE-OID decoder 
(CVE-2026-23490)
+    (Closes: #1125753)
+
+ -- Salvatore Bonaccorso <[email protected]>  Mon, 19 Jan 2026 07:01:31 +0100
+
 pyasn1 (0.6.1-1) unstable; urgency=medium
 
   * Team upload.
diff -Nru pyasn1-0.6.1/debian/patches/CVE-2026-23490.patch 
pyasn1-0.6.1/debian/patches/CVE-2026-23490.patch
--- pyasn1-0.6.1/debian/patches/CVE-2026-23490.patch    1970-01-01 
01:00:00.000000000 +0100
+++ pyasn1-0.6.1/debian/patches/CVE-2026-23490.patch    2026-01-19 
06:59:04.000000000 +0100
@@ -0,0 +1,219 @@
+From: Simon Pichugin <[email protected]>
+Date: Fri, 16 Jan 2026 08:57:23 -0800
+Subject: Merge commit from fork
+Origin: 
https://github.com/pyasn1/pyasn1/commit/3908f144229eed4df24bd569d16e5991ace44970
+Bug-Debian: https://bugs.debian.org/1125753
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-23490
+
+Add limit of 20 continuation octets per OID arc to prevent a potential memory
+exhaustion from excessive continuation bytes input.
+---
+ pyasn1/codec/ber/decoder.py     |  20 ++++-
+ tests/codec/ber/test_decoder.py | 130 ++++++++++++++++++++++++++++++++
+ 2 files changed, 149 insertions(+), 1 deletion(-)
+
+diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py
+index 7e69ca156785..853e837b07c6 100644
+--- a/pyasn1/codec/ber/decoder.py
++++ b/pyasn1/codec/ber/decoder.py
+@@ -33,6 +33,10 @@ noValue = base.noValue
+ 
+ SubstrateUnderrunError = error.SubstrateUnderrunError
+ 
++# Maximum number of continuation octets (high-bit set) allowed per OID arc.
++# 20 octets allows up to 140-bit integers, supporting UUID-based OIDs
++MAX_OID_ARC_CONTINUATION_OCTETS = 20
++
+ 
+ class AbstractPayloadDecoder(object):
+     protoComponent = None
+@@ -427,7 +431,14 @@ class 
ObjectIdentifierPayloadDecoder(AbstractSimplePayloadDecoder):
+                 # Construct subid from a number of octets
+                 nextSubId = subId
+                 subId = 0
++                continuationOctetCount = 0
+                 while nextSubId >= 128:
++                    continuationOctetCount += 1
++                    if continuationOctetCount > 
MAX_OID_ARC_CONTINUATION_OCTETS:
++                        raise error.PyAsn1Error(
++                            'OID arc exceeds maximum continuation octets 
limit (%d) '
++                            'at position %d' % 
(MAX_OID_ARC_CONTINUATION_OCTETS, index)
++                        )
+                     subId = (subId << 7) + (nextSubId & 0x7F)
+                     if index >= substrateLen:
+                         raise error.SubstrateUnderrunError(
+@@ -485,7 +496,14 @@ class 
RelativeOIDPayloadDecoder(AbstractSimplePayloadDecoder):
+                 # Construct subid from a number of octets
+                 nextSubId = subId
+                 subId = 0
++                continuationOctetCount = 0
+                 while nextSubId >= 128:
++                    continuationOctetCount += 1
++                    if continuationOctetCount > 
MAX_OID_ARC_CONTINUATION_OCTETS:
++                        raise error.PyAsn1Error(
++                            'RELATIVE-OID arc exceeds maximum continuation 
octets limit (%d) '
++                            'at position %d' % 
(MAX_OID_ARC_CONTINUATION_OCTETS, index)
++                        )
+                     subId = (subId << 7) + (nextSubId & 0x7F)
+                     if index >= substrateLen:
+                         raise error.SubstrateUnderrunError(
+@@ -1915,7 +1933,7 @@ class StreamingDecoder(object):
+         :py:class:`~pyasn1.error.SubstrateUnderrunError` object indicating
+         insufficient BER/CER/DER serialization on input to fully recover ASN.1
+         objects from it.
+-        
++
+         In the latter case the caller is advised to ensure some more data in
+         the input stream, then call the iterator again. The decoder will 
resume
+         the decoding process using the newly arrived data.
+diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py
+index f69da1102051..741605f313ed 100644
+--- a/tests/codec/ber/test_decoder.py
++++ b/tests/codec/ber/test_decoder.py
+@@ -449,6 +449,72 @@ class ObjectIdentifierDecoderTestCase(BaseTestCase):
+             bytes((0x06, 0x13, 0x88, 0x37, 0x83, 0xC6, 0xDF, 0xD4, 0xCC, 
0xB3, 0xFF, 0xFF, 0xFE, 0xF0, 0xB8, 0xD6, 0xB8, 0xCB, 0xE2, 0xB6, 0x47))
+         ) == ((2, 999, 18446744073709551535184467440737095), b'')
+ 
++    def testExcessiveContinuationOctets(self):
++        """Test that OID arcs with excessive continuation octets are 
rejected."""
++        # Create a payload with 25 continuation octets (exceeds 20 limit)
++        # 0x81 bytes are continuation octets, 0x01 terminates
++        malicious_payload = bytes([0x06, 26]) + bytes([0x81] * 25) + 
bytes([0x01])
++        try:
++            decoder.decode(malicious_payload)
++        except error.PyAsn1Error:
++            pass
++        else:
++            assert 0, 'Excessive continuation octets tolerated'
++
++    def testMaxAllowedContinuationOctets(self):
++        """Test that OID arcs at the maximum continuation octets limit 
work."""
++        # Create a payload with exactly 20 continuation octets (at limit)
++        # This should succeed
++        payload = bytes([0x06, 21]) + bytes([0x81] * 20) + bytes([0x01])
++        try:
++            decoder.decode(payload)
++        except error.PyAsn1Error:
++            assert 0, 'Valid OID with 20 continuation octets rejected'
++
++    def testOneOverContinuationLimit(self):
++        """Test boundary: 21 continuation octets (one over limit) is 
rejected."""
++        payload = bytes([0x06, 22]) + bytes([0x81] * 21) + bytes([0x01])
++        try:
++            decoder.decode(payload)
++        except error.PyAsn1Error:
++            pass
++        else:
++            assert 0, '21 continuation octets tolerated (should be rejected)'
++
++    def testExcessiveContinuationInSecondArc(self):
++        """Test that limit applies to subsequent arcs, not just the first."""
++        # First arc: valid simple byte (0x55 = 85, decodes to arc 2.5)
++        # Second arc: excessive continuation octets
++        payload = bytes([0x06, 27]) + bytes([0x55]) + bytes([0x81] * 25) + 
bytes([0x01])
++        try:
++            decoder.decode(payload)
++        except error.PyAsn1Error:
++            pass
++        else:
++            assert 0, 'Excessive continuation in second arc tolerated'
++
++    def testMultipleArcsAtLimit(self):
++        """Test multiple arcs each at the continuation limit work 
correctly."""
++        # Two arcs, each with 20 continuation octets (both at limit)
++        arc1 = bytes([0x81] * 20) + bytes([0x01])  # 21 bytes
++        arc2 = bytes([0x81] * 20) + bytes([0x01])  # 21 bytes
++        payload = bytes([0x06, 42]) + arc1 + arc2
++        try:
++            decoder.decode(payload)
++        except error.PyAsn1Error:
++            assert 0, 'Multiple valid arcs at limit rejected'
++
++    def testExcessiveContinuationWithMaxBytes(self):
++        """Test with 0xFF continuation bytes (maximum value, not just 
0x81)."""
++        # 0xFF bytes are also continuation octets (high bit set)
++        malicious_payload = bytes([0x06, 26]) + bytes([0xFF] * 25) + 
bytes([0x01])
++        try:
++            decoder.decode(malicious_payload)
++        except error.PyAsn1Error:
++            pass
++        else:
++            assert 0, 'Excessive 0xFF continuation octets tolerated'
++
+ 
+ class RelativeOIDDecoderTestCase(BaseTestCase):
+     def testOne(self):
+@@ -518,6 +584,70 @@ class RelativeOIDDecoderTestCase(BaseTestCase):
+             bytes((0x0D, 0x13, 0x88, 0x37, 0x83, 0xC6, 0xDF, 0xD4, 0xCC, 
0xB3, 0xFF, 0xFF, 0xFE, 0xF0, 0xB8, 0xD6, 0xB8, 0xCB, 0xE2, 0xB6, 0x47))
+         ) == ((1079, 18446744073709551535184467440737095), b'')
+ 
++    def testExcessiveContinuationOctets(self):
++        """Test that RELATIVE-OID arcs with excessive continuation octets are 
rejected."""
++        # Create a payload with 25 continuation octets (exceeds 20 limit)
++        malicious_payload = bytes([0x0D, 26]) + bytes([0x81] * 25) + 
bytes([0x01])
++        try:
++            decoder.decode(malicious_payload)
++        except error.PyAsn1Error:
++            pass
++        else:
++            assert 0, 'Excessive continuation octets tolerated'
++
++    def testMaxAllowedContinuationOctets(self):
++        """Test that RELATIVE-OID arcs at the maximum continuation octets 
limit work."""
++        # Create a payload with exactly 20 continuation octets (at limit)
++        payload = bytes([0x0D, 21]) + bytes([0x81] * 20) + bytes([0x01])
++        try:
++            decoder.decode(payload)
++        except error.PyAsn1Error:
++            assert 0, 'Valid RELATIVE-OID with 20 continuation octets 
rejected'
++
++    def testOneOverContinuationLimit(self):
++        """Test boundary: 21 continuation octets (one over limit) is 
rejected."""
++        payload = bytes([0x0D, 22]) + bytes([0x81] * 21) + bytes([0x01])
++        try:
++            decoder.decode(payload)
++        except error.PyAsn1Error:
++            pass
++        else:
++            assert 0, '21 continuation octets tolerated (should be rejected)'
++
++    def testExcessiveContinuationInSecondArc(self):
++        """Test that limit applies to subsequent arcs, not just the first."""
++        # First arc: valid simple byte
++        # Second arc: excessive continuation octets
++        payload = bytes([0x0D, 27]) + bytes([0x55]) + bytes([0x81] * 25) + 
bytes([0x01])
++        try:
++            decoder.decode(payload)
++        except error.PyAsn1Error:
++            pass
++        else:
++            assert 0, 'Excessive continuation in second arc tolerated'
++
++    def testMultipleArcsAtLimit(self):
++        """Test multiple arcs each at the continuation limit work 
correctly."""
++        # Two arcs, each with 20 continuation octets (both at limit)
++        arc1 = bytes([0x81] * 20) + bytes([0x01])  # 21 bytes
++        arc2 = bytes([0x81] * 20) + bytes([0x01])  # 21 bytes
++        payload = bytes([0x0D, 42]) + arc1 + arc2
++        try:
++            decoder.decode(payload)
++        except error.PyAsn1Error:
++            assert 0, 'Multiple valid arcs at limit rejected'
++
++    def testExcessiveContinuationWithMaxBytes(self):
++        """Test with 0xFF continuation bytes (maximum value, not just 
0x81)."""
++        # 0xFF bytes are also continuation octets (high bit set)
++        malicious_payload = bytes([0x0D, 26]) + bytes([0xFF] * 25) + 
bytes([0x01])
++        try:
++            decoder.decode(malicious_payload)
++        except error.PyAsn1Error:
++            pass
++        else:
++            assert 0, 'Excessive 0xFF continuation octets tolerated'
++
+ 
+ class RealDecoderTestCase(BaseTestCase):
+     def testChar(self):
+-- 
+2.51.0
+
diff -Nru pyasn1-0.6.1/debian/patches/series pyasn1-0.6.1/debian/patches/series
--- pyasn1-0.6.1/debian/patches/series  2024-08-22 13:55:22.000000000 +0200
+++ pyasn1-0.6.1/debian/patches/series  2026-01-19 06:59:13.000000000 +0100
@@ -1 +1,2 @@
 0002-Remove-some-theme-options-to-avoid-needless-badges-i.patch
+CVE-2026-23490.patch

Reply via email to