diff --git a/meta/recipes-devtools/python/python-pyasn1.inc b/meta/recipes-devtools/python/python-pyasn1.inc
index 1780ee1d88..ae96f09fb1 100644
--- a/meta/recipes-devtools/python/python-pyasn1.inc
+++ b/meta/recipes-devtools/python/python-pyasn1.inc
@@ -20,6 +20,7 @@ SRC_URI += " \
        file://run-ptest \
        file://CVE-2026-23490.patch \
        file://CVE-2026-59886.patch \
+       file://CVE-2026-59884.patch \
 "
 
 RDEPENDS:${PN}-ptest += " \
diff --git a/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-59884.patch b/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-59884.patch
new file mode 100644
index 0000000000..dd897e2d75
--- /dev/null
+++ b/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-59884.patch
@@ -0,0 +1,245 @@
+From 38e8ae286160eb27620e7cb42108b3b28d1f299f Mon Sep 17 00:00:00 2001
+From: Simon Pichugin <simon.pichugin@gmail.com>
+Date: Wed, 8 Jul 2026 17:36:30 -0700
+Subject: [PATCH] Merge commit from fork
+
+CVE: CVE-2026-59884
+Upstream-Status: Backport [https://github.com/pyasn1/pyasn1/commit/628e36ecbb5277a3f01572ce418ef54271b165a5]
+
+(cherry picked from commit 628e36ecbb5277a3f01572ce418ef54271b165a5)
+Signed-off-by: Emily Vekariya <evekariy@cisco.com>
+---
+ pyasn1/codec/ber/decoder.py     | 13 +++++++++++--
+ pyasn1/type/tag.py              | 20 ++++++++++++++++----
+ tests/codec/ber/test_decoder.py | 25 +++++++++++++++++++++++++
+ tests/codec/cer/test_decoder.py | 15 +++++++++++++++
+ tests/codec/der/test_decoder.py | 15 +++++++++++++++
+ tests/type/test_tag.py          | 20 ++++++++++++++++++++
+ 6 files changed, 102 insertions(+), 6 deletions(-)
+
+diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py
+index be8ba65..18865c2 100644
+--- a/pyasn1/codec/ber/decoder.py
++++ b/pyasn1/codec/ber/decoder.py
+@@ -39,6 +39,10 @@ SubstrateUnderrunError = error.SubstrateUnderrunError
+ # 20 octets allows up to 140-bit integers, supporting UUID-based OIDs
+ MAX_OID_ARC_CONTINUATION_OCTETS = 20
+ 
++# Maximum number of octets in a long-form tag ID (20 octets = up to
++# 140-bit tag IDs, matching the OID arc limit)
++MAX_TAG_OCTETS = 20
++
+ 
+ class AbstractPayloadDecoder(object):
+     protoComponent = None
+@@ -1570,7 +1574,7 @@ class SingleItemDecoder(object):
+ 
+                     if tagId == 0x1F:
+                         isShortTag = False
+-                        lengthOctetIdx = 0
++                        tagOctetCount = 0
+                         tagId = 0
+ 
+                         while True:
+@@ -1584,7 +1588,12 @@ class SingleItemDecoder(object):
+                                 )
+ 
+                             integerTag = ord(integerByte)
+-                            lengthOctetIdx += 1
++                            tagOctetCount += 1
++                            if tagOctetCount > MAX_TAG_OCTETS:
++                                raise error.PyAsn1Error(
++                                    'Tag ID octet count exceeds limit (%d)' % (
++                                        MAX_TAG_OCTETS,)
++                                )
+                             tagId <<= 7
+                             tagId |= (integerTag & 0x7F)
+ 
+diff --git a/pyasn1/type/tag.py b/pyasn1/type/tag.py
+index a21a405..bbbdd85 100644
+--- a/pyasn1/type/tag.py
++++ b/pyasn1/type/tag.py
+@@ -34,6 +34,16 @@ tagCategoryExplicit = 0x02
+ tagCategoryUntagged = 0x04
+ 
+ 
++def _tagIdToStr(tagId):
++    # Decimal rendering of a huge tag ID can exceed the interpreter's
++    # integer-to-string conversion limit (sys.get_int_max_str_digits(),
++    # Python 3.11+) and raise ValueError; hexadecimal is not limited
++    try:
++        return str(tagId)
++    except ValueError:
++        return hex(tagId)
++
++
+ class Tag(object):
+     """Create ASN.1 tag
+ 
+@@ -56,7 +66,8 @@ class Tag(object):
+     """
+     def __init__(self, tagClass, tagFormat, tagId):
+         if tagId < 0:
+-            raise error.PyAsn1Error('Negative tag ID (%s) not allowed' % tagId)
++            raise error.PyAsn1Error(
++                'Negative tag ID (%s) not allowed' % _tagIdToStr(tagId))
+         self.__tagClass = tagClass
+         self.__tagFormat = tagFormat
+         self.__tagId = tagId
+@@ -65,7 +76,7 @@ class Tag(object):
+ 
+     def __repr__(self):
+         representation = '[%s:%s:%s]' % (
+-            self.__tagClass, self.__tagFormat, self.__tagId)
++            self.__tagClass, self.__tagFormat, _tagIdToStr(self.__tagId))
+         return '<%s object, tag %s>' % (
+             self.__class__.__name__, representation)
+ 
+@@ -194,8 +205,9 @@ class TagSet(object):
+         self.__hash = hash(self.__superTagsClassId)
+ 
+     def __repr__(self):
+-        representation = '-'.join(['%s:%s:%s' % (x.tagClass, x.tagFormat, x.tagId)
+-                                   for x in self.__superTags])
++        representation = '-'.join(
++            ['%s:%s:%s' % (x.tagClass, x.tagFormat, _tagIdToStr(x.tagId))
++             for x in self.__superTags])
+         if representation:
+             representation = 'tags ' + representation
+         else:
+diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py
+index f6ff7b0..0152027 100644
+--- a/tests/codec/ber/test_decoder.py
++++ b/tests/codec/ber/test_decoder.py
+@@ -34,6 +34,31 @@ class LargeTagDecoderTestCase(BaseTestCase):
+     def testLongTag(self):
+         assert decoder.decode(ints2octs((0x1f, 2, 1, 0)))[0].tagSet == univ.Integer.tagSet
+ 
++    def testVeryLongTagRoundTrip(self):
++        # (1 << 140) - 1 is the largest tag ID fitting the 20 octet limit
++        for tagId in (1 << 77, (1 << 140) - 1):
++            largeTag = tag.Tag(tag.tagClassContext, tag.tagFormatSimple, tagId)
++            asn1Spec = univ.Integer().subtype(implicitTag=largeTag)
++            value = univ.Integer(1).subtype(implicitTag=largeTag)
++
++            decoded, rest = decoder.decode(encoder.encode(value), asn1Spec=asn1Spec)
++
++            assert rest == b''
++            assert decoded == 1
++
++    def testExcessiveLongTag(self):
++        # 1 << 140 is the smallest tag ID needing 21 octets, one over the limit
++        excessiveTag = tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1 << 140)
++        asn1Spec = univ.Integer().subtype(implicitTag=excessiveTag)
++        substrate = encoder.encode(univ.Integer(1).subtype(implicitTag=excessiveTag))
++
++        try:
++            decoder.decode(substrate, asn1Spec=asn1Spec)
++        except error.PyAsn1Error:
++            pass
++        else:
++            assert 0, 'excessive long tag tolerated'
++
+     def testTagsEquivalence(self):
+         integer = univ.Integer(2).subtype(implicitTag=tag.Tag(tag.tagClassContext, 0, 0))
+         assert decoder.decode(ints2octs((0x9f, 0x80, 0x00, 0x02, 0x01, 0x02)), asn1Spec=integer) == decoder.decode(
+diff --git a/tests/codec/cer/test_decoder.py b/tests/codec/cer/test_decoder.py
+index 3d27194..d759f76 100644
+--- a/tests/codec/cer/test_decoder.py
++++ b/tests/codec/cer/test_decoder.py
+@@ -67,6 +67,21 @@ class OctetStringDecoderTestCase(BaseTestCase):
+     # TODO: test failures on short chunked and long unchunked substrate samples
+ 
+ 
++class LargeTagDecoderTestCase(BaseTestCase):
++    def testExcessiveLongTag(self):
++        # 1 << 140 is the smallest tag ID needing 21 octets, one over the limit
++        excessiveTag = tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1 << 140)
++        asn1Spec = univ.Integer().subtype(implicitTag=excessiveTag)
++        substrate = encoder.encode(univ.Integer(1).subtype(implicitTag=excessiveTag))
++
++        try:
++            decoder.decode(substrate, asn1Spec=asn1Spec)
++        except PyAsn1Error:
++            pass
++        else:
++            assert 0, 'excessive long tag tolerated'
++
++
+ class RealDecoderTestCase(BaseTestCase):
+     def testLargeBinaryRoundTrip(self):
+         substrate = encoder.encode(univ.Real((-1, 2, 76354972)))
+diff --git a/tests/codec/der/test_decoder.py b/tests/codec/der/test_decoder.py
+index 553563c..726c999 100644
+--- a/tests/codec/der/test_decoder.py
++++ b/tests/codec/der/test_decoder.py
+@@ -73,6 +73,21 @@ class OctetStringDecoderTestCase(BaseTestCase):
+             assert 0, 'chunked encoding tolerated'
+ 
+ 
++class LargeTagDecoderTestCase(BaseTestCase):
++    def testExcessiveLongTag(self):
++        # 1 << 140 is the smallest tag ID needing 21 octets, one over the limit
++        excessiveTag = tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1 << 140)
++        asn1Spec = univ.Integer().subtype(implicitTag=excessiveTag)
++        substrate = encoder.encode(univ.Integer(1).subtype(implicitTag=excessiveTag))
++
++        try:
++            decoder.decode(substrate, asn1Spec=asn1Spec)
++        except PyAsn1Error:
++            pass
++        else:
++            assert 0, 'excessive long tag tolerated'
++
++
+ class RealDecoderTestCase(BaseTestCase):
+     def testCanonicalLargeBinaryReal(self):
+         substrate = encoder.encode(univ.Real((1, 2, 1000000)))
+diff --git a/tests/type/test_tag.py b/tests/type/test_tag.py
+index d0ffa07..ab9b8b1 100644
+--- a/tests/type/test_tag.py
++++ b/tests/type/test_tag.py
+@@ -9,6 +9,7 @@ import unittest
+ 
+ from tests.base import BaseTestCase
+ 
++from pyasn1 import error
+ from pyasn1.type import tag
+ 
+ 
+@@ -23,6 +24,19 @@ class TagReprTestCase(TagTestCaseBase):
+     def testRepr(self):
+         assert 'Tag' in repr(self.t1)
+ 
++    def testReprHugeTagId(self):
++        # must not hit the interpreter's int-to-str conversion limit
++        hugeTag = tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1 << 100000)
++        assert 'Tag' in repr(hugeTag)
++
++    def testNegativeHugeTagId(self):
++        try:
++            tag.Tag(tag.tagClassContext, tag.tagFormatSimple, -(1 << 100000))
++        except error.PyAsn1Error:
++            pass
++        else:
++            assert 0, 'negative tag ID tolerated'
++
+ 
+ class TagCmpTestCase(TagTestCaseBase):
+     def testCmp(self):
+@@ -54,6 +68,12 @@ class TagSetReprTestCase(TagSetTestCaseBase):
+     def testRepr(self):
+         assert 'TagSet' in repr(self.ts1)
+ 
++    def testReprHugeTagId(self):
++        # must not hit the interpreter's int-to-str conversion limit
++        hugeTagSet = self.ts1.tagImplicitly(
++            tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1 << 100000))
++        assert 'TagSet' in repr(hugeTagSet)
++
+ 
+ class TagSetCmpTestCase(TagSetTestCaseBase):
+     def testCmp(self):
+-- 
+2.34.1
+
