File 0001-Fix-CVE-2025-13836-CVE-2025-12084-and-CVE-2025-13837.patch of Package python3.42041
From 532519872b4ba51479f55dd419ce77f1537f676a1589f4960590547689e58358 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= <mcepl@cepl.eu>
Date: Thu, 18 Dec 2025 16:07:31 +0100
Subject: [PATCH] Fix CVE-2025-13836, CVE-2025-12084, and CVE-2025-13837.
- Add CVE-2025-13836-http-resp-cont-len.patch (bsc#1254400,
CVE-2025-13836) to prevent reading an HTTP response from
a server, if no read amount is specified, with using
Content-Length per default as the length.
- Add CVE-2025-12084-minidom-quad-search.patch prevent quadratic
behavior in node ID cache clearing (CVE-2025-12084,
bsc#1254997).
- Add CVE-2025-13837-plistlib-mailicious-length.patch protect
against OOM when loading malicious content (CVE-2025-13837,
bsc#1254401).
---
CVE-2025-12084-minidom-quad-search.patch | 93 +++++++
CVE-2025-13836-http-resp-cont-len.patch | 258 ++++++++++++++++++
...025-13837-plistlib-mailicious-length.patch | 161 +++++++++++
python36.changes | 14 +
python36.spec | 9 +
5 files changed, 535 insertions(+)
create mode 100644 CVE-2025-12084-minidom-quad-search.patch
create mode 100644 CVE-2025-13836-http-resp-cont-len.patch
create mode 100644 CVE-2025-13837-plistlib-mailicious-length.patch
diff --git a/CVE-2025-12084-minidom-quad-search.patch b/CVE-2025-12084-minidom-quad-search.patch
new file mode 100644
index 0000000..adc9631
--- /dev/null
+++ b/CVE-2025-12084-minidom-quad-search.patch
@@ -0,0 +1,93 @@
+From f4eb9ab014545b521fb261b80adfa6d138e7e092 Mon Sep 17 00:00:00 2001
+From: Seth Michael Larson <seth@python.org>
+Date: Wed, 3 Dec 2025 01:16:37 -0600
+Subject: [PATCH] gh-142145: Remove quadratic behavior in node ID cache
+ clearing (GH-142146)
+
+* Remove quadratic behavior in node ID cache clearing
+
+Co-authored-by: Jacob Walls <38668450+jacobtylerwalls@users.noreply.github.com>
+
+* Add news fragment
+
+---------
+(cherry picked from commit 08d8e18ad81cd45bc4a27d6da478b51ea49486e4)
+
+Co-authored-by: Seth Michael Larson <seth@python.org>
+Co-authored-by: Jacob Walls <38668450+jacobtylerwalls@users.noreply.github.com>
+---
+ Lib/test/test_minidom.py | 18 ++++++++++
+ Lib/xml/dom/minidom.py | 9 -----
+ Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst | 1
+ 3 files changed, 20 insertions(+), 8 deletions(-)
+ create mode 100644 Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst
+
+Index: Python-3.6.15/Lib/test/test_minidom.py
+===================================================================
+--- Python-3.6.15.orig/Lib/test/test_minidom.py 2025-12-20 20:02:31.594672148 +0100
++++ Python-3.6.15/Lib/test/test_minidom.py 2025-12-20 20:04:27.310278898 +0100
+@@ -2,6 +2,7 @@
+
+ import copy
+ import pickle
++import time
+ from test import support
+ import unittest
+
+@@ -171,6 +172,23 @@
+ self.confirm(dom.documentElement.childNodes[-1].data == "Hello")
+ dom.unlink()
+
++ def testAppendChildNoQuadraticComplexity(self):
++ impl = getDOMImplementation()
++
++ newdoc = impl.createDocument(None, "some_tag", None)
++ top_element = newdoc.documentElement
++ children = [newdoc.createElement(f"child-{i}") for i in range(1, 2 ** 15 + 1)]
++ element = top_element
++
++ start = time.time()
++ for child in children:
++ element.appendChild(child)
++ element = child
++ end = time.time()
++
++ # This example used to take at least 30 seconds.
++ self.assertLess(end - start, 1)
++
+ def testAppendChildFragment(self):
+ dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
+ dom.documentElement.appendChild(frag)
+Index: Python-3.6.15/Lib/xml/dom/minidom.py
+===================================================================
+--- Python-3.6.15.orig/Lib/xml/dom/minidom.py 2025-12-20 20:02:31.594672148 +0100
++++ Python-3.6.15/Lib/xml/dom/minidom.py 2025-12-20 20:04:27.311120771 +0100
+@@ -291,13 +291,6 @@
+ childNodes.append(node)
+ node.parentNode = self
+
+-def _in_document(node):
+- # return True iff node is part of a document tree
+- while node is not None:
+- if node.nodeType == Node.DOCUMENT_NODE:
+- return True
+- node = node.parentNode
+- return False
+
+ def _write_data(writer, data):
+ "Writes datachars to writer."
+@@ -1512,7 +1505,7 @@
+ if node.nodeType == Node.DOCUMENT_NODE:
+ node._id_cache.clear()
+ node._id_search_stack = None
+- elif _in_document(node):
++ elif node.ownerDocument:
+ node.ownerDocument._id_cache.clear()
+ node.ownerDocument._id_search_stack= None
+
+Index: Python-3.6.15/Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ Python-3.6.15/Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst 2025-12-20 20:04:27.311549530 +0100
+@@ -0,0 +1 @@
++Remove quadratic behavior in ``xml.minidom`` node ID cache clearing.
diff --git a/CVE-2025-13836-http-resp-cont-len.patch b/CVE-2025-13836-http-resp-cont-len.patch
new file mode 100644
index 0000000..dc731fd
--- /dev/null
+++ b/CVE-2025-13836-http-resp-cont-len.patch
@@ -0,0 +1,258 @@
+From b3a7998115e195c40e00cfa662bcaa899d937c05 Mon Sep 17 00:00:00 2001
+From: Serhiy Storchaka <storchaka@gmail.com>
+Date: Mon, 1 Dec 2025 17:26:07 +0200
+Subject: [PATCH] gh-119451: Fix a potential denial of service in http.client
+ (GH-119454)
+
+Reading the whole body of the HTTP response could cause OOM if
+the Content-Length value is too large even if the server does not send
+a large amount of data. Now the HTTP client reads large data by chunks,
+therefore the amount of consumed memory is proportional to the amount
+of sent data.
+(cherry picked from commit 5a4c4a033a4a54481be6870aa1896fad732555b5)
+
+Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
+---
+ Lib/http/client.py | 32 ++
+ Lib/test/test_httplib.py | 116 ++++++++++
+ Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst | 5
+ Lib/http/client.py | 32 +++-
+ Lib/socket.py | 56 ++++++++
+ Lib/test/test_httplib.py | 67 ++++++++++
+ Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst | 5
+ Lib/http/client.py | 32 +++-
+ Lib/socket.py | 55 ++++++++
+ Lib/test/test_httplib.py | 67 ++++++++++
+ Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst | 5
+ Lib/http/client.py | 32 +++-
+ Lib/socket.py | 55 ++++++++
+ Lib/test/test_httplib.py | 67 ++++++++++
+ Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst | 5
+ Lib/http/client.py | 32 +++-
+ Lib/socket.py | 63 ++++++++-
+ Lib/test/test_httplib.py | 67 ++++++++++
+ Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst | 5
+ 4 files changed, 154 insertions(+), 13 deletions(-)
+ create mode 100644 Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst
+
+Index: Python-3.6.15/Lib/http/client.py
+===================================================================
+--- Python-3.6.15.orig/Lib/http/client.py 2025-12-20 21:50:29.594974409 +0100
++++ Python-3.6.15/Lib/http/client.py 2025-12-20 21:51:56.521473590 +0100
+@@ -113,6 +113,11 @@
+ _MAXLINE = 65536
+ _MAXHEADERS = 100
+
++# Data larger than this will be read in chunks, to prevent extreme
++# overallocation.
++_MIN_READ_BUF_SIZE = 1 << 20
++
++
+ # Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2)
+ #
+ # VCHAR = %x21-7E
+@@ -625,14 +630,25 @@
+ reading. If the bytes are truly not available (due to EOF), then the
+ IncompleteRead exception can be used to detect the problem.
+ """
+- s = []
+- while amt > 0:
+- chunk = self.fp.read(min(amt, MAXAMOUNT))
+- if not chunk:
+- raise IncompleteRead(b''.join(s), amt)
+- s.append(chunk)
+- amt -= len(chunk)
+- return b"".join(s)
++ cursize = min(amt, _MIN_READ_BUF_SIZE)
++ data = self.fp.read(cursize)
++ if len(data) >= amt:
++ return data
++ if len(data) < cursize:
++ raise IncompleteRead(data, amt - len(data))
++
++ data = io.BytesIO(data)
++ data.seek(0, 2)
++ while True:
++ # This is a geometric increase in read size (never more than
++ # doubling out the current length of data per loop iteration).
++ delta = min(cursize, amt - cursize)
++ data.write(self.fp.read(delta))
++ if data.tell() >= amt:
++ return data.getvalue()
++ cursize += delta
++ if data.tell() < cursize:
++ raise IncompleteRead(data.getvalue(), amt - data.tell())
+
+ def _safe_readinto(self, b):
+ """Same as _safe_read, but for reading into a buffer."""
+Index: Python-3.6.15/Lib/socket.py
+===================================================================
+--- Python-3.6.15.orig/Lib/socket.py 2025-12-20 21:50:28.817654367 +0100
++++ Python-3.6.15/Lib/socket.py 2025-12-20 23:21:42.522134097 +0100
+@@ -26,6 +26,7 @@
+ socket.setdefaulttimeout() -- set the default timeout value
+ create_connection() -- connects to an address, with an optional timeout and
+ optional source address.
++create_server() -- create a TCP socket and bind it to a specified address.
+
+ [*] not available on all platforms!
+
+@@ -742,9 +743,61 @@
+ # We override this function since we want to translate the numeric family
+ # and socket type values to enum constants.
+ addrlist = []
+- for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
++
++
++def create_server(address, family=None, backlog=None, reuse_port=False):
++ """Convenience function which creates a SOCK_STREAM type socket
++ bound to *address* (a 2-tuple (host, port)) and return the socket
++ object.
++
++ *family* should be either AF_INET or AF_INET6.
++ *backlog* is the queue size passed to socket.listen().
++ *reuse_port* dictates whether to use the SO_REUSEPORT socket option.
++ *dualstack_ipv6*: if true and the platform supports it, it will
++ create an AF_INET6 socket able to accept both IPv4 or IPv6
++ connections. When false it will explicitly disable this option on
++ platforms that enable it by default (e.g. Linux).
++
++ >>> with create_server(('', 8000)) as server:
++ ... while True:
++ ... conn, addr = server.accept()
++ ... # handle new connection
++ """
++ if family is None:
++ family = getattr(socket, 'AF_UNSPEC', 0)
++ host, port = address
++ # Use getaddrinfo to resolve the address and automatically handle family.
++ # AI_PASSIVE is used for server-side bind() calls.
++ err = None
++
++ try:
++ addr_infos = socket.getaddrinfo( host, port, family, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
++ except socket.gaierror as e:
++ raise OSError("getaddrinfo failed for {}: {}".format(address, e))
++ for res in addr_infos:
+ af, socktype, proto, canonname, sa = res
+- addrlist.append((_intenum_converter(af, AddressFamily),
+- _intenum_converter(socktype, SocketKind),
+- proto, canonname, sa))
+- return addrlist
++ sock = None
++ try:
++ sock = socket.socket(af, socktype, proto)
++
++ # Set SO_REUSEADDR, which is critical for server sockets
++ # to allow reuse of the address soon after a close.
++ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
++
++ if reuse_port:
++ if hasattr(socket, "SO_REUSEPORT"):
++ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
++
++ sock.bind(sa)
++ sock.listen(backlog if backlog is not None else socket.SOMAXCONN)
++
++ return sock # Return the successfully bound socket
++ except OSError as e:
++ err = e
++ if sock is not None:
++ sock.close()
++
++ # If we get here, no address worked
++ if err is not None:
++ raise err
++ raise OSError("getaddrinfo failed for address {}".format(address))
+Index: Python-3.6.15/Lib/test/test_httplib.py
+===================================================================
+--- Python-3.6.15.orig/Lib/test/test_httplib.py 2025-12-20 21:50:31.087796745 +0100
++++ Python-3.6.15/Lib/test/test_httplib.py 2025-12-20 21:51:56.523473580 +0100
+@@ -1167,6 +1167,72 @@
+ thread.join()
+ self.assertEqual(result, b"proxied data\n")
+
++ def test_large_content_length(self):
++ serv = socket.create_server((HOST, 0))
++ self.addCleanup(serv.close)
++
++ def run_server():
++ [conn, address] = serv.accept()
++ with conn:
++ while conn.recv(1024):
++ conn.sendall(
++ b"HTTP/1.1 200 Ok\r\n"
++ b"Content-Length: %d\r\n"
++ b"\r\n" % size)
++ conn.sendall(b'A' * (size//3))
++ conn.sendall(b'B' * (size - size//3))
++
++ thread = threading.Thread(target=run_server)
++ thread.start()
++ self.addCleanup(thread.join, 1.0)
++
++ conn = client.HTTPConnection(*serv.getsockname())
++ try:
++ for w in range(15, 27):
++ size = 1 << w
++ conn.request("GET", "/")
++ with conn.getresponse() as response:
++ self.assertEqual(len(response.read()), size)
++ finally:
++ conn.close()
++ thread.join(1.0)
++
++ def test_large_content_length_truncated(self):
++ serv = socket.create_server((HOST, 0))
++ self.addCleanup(serv.close)
++
++ def run_server():
++ while True:
++ [conn, address] = serv.accept()
++ with conn:
++ conn.recv(1024)
++ if not size:
++ break
++ conn.sendall(
++ b"HTTP/1.1 200 Ok\r\n"
++ b"Content-Length: %d\r\n"
++ b"\r\n"
++ b"Text" % size)
++
++ thread = threading.Thread(target=run_server)
++ thread.start()
++ self.addCleanup(thread.join, 1.0)
++
++ conn = client.HTTPConnection(*serv.getsockname())
++ try:
++ for w in range(18, 65):
++ size = 1 << w
++ conn.request("GET", "/")
++ with conn.getresponse() as response:
++ self.assertRaises(client.IncompleteRead, response.read)
++ conn.close()
++ finally:
++ conn.close()
++ size = 0
++ conn.request("GET", "/")
++ conn.close()
++ thread.join(1.0)
++
+ def test_putrequest_override_domain_validation(self):
+ """
+ It should be possible to override the default validation
+@@ -1991,3 +2057,4 @@
+
+ if __name__ == '__main__':
+ unittest.main(verbosity=2)
++
+Index: Python-3.6.15/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ Python-3.6.15/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst 2025-12-20 21:51:56.524131559 +0100
+@@ -0,0 +1,5 @@
++Fix a potential memory denial of service in the :mod:`http.client` module.
++When connecting to a malicious server, it could cause
++an arbitrary amount of memory to be allocated.
++This could have led to symptoms including a :exc:`MemoryError`, swapping, out
++of memory (OOM) killed processes or containers, or even system crashes.
diff --git a/CVE-2025-13837-plistlib-mailicious-length.patch b/CVE-2025-13837-plistlib-mailicious-length.patch
new file mode 100644
index 0000000..0408b7f
--- /dev/null
+++ b/CVE-2025-13837-plistlib-mailicious-length.patch
@@ -0,0 +1,161 @@
+From e99059d800b741504ef18693803927a0dc062be4 Mon Sep 17 00:00:00 2001
+From: Serhiy Storchaka <storchaka@gmail.com>
+Date: Mon, 1 Dec 2025 17:28:15 +0200
+Subject: [PATCH] [3.10] gh-119342: Fix a potential denial of service in
+ plistlib (GH-119343)
+
+Reading a specially prepared small Plist file could cause OOM because file's
+read(n) preallocates a bytes object for reading the specified amount of
+data. Now plistlib reads large data by chunks, therefore the upper limit of
+consumed memory is proportional to the size of the input file.
+(cherry picked from commit 694922cf40aa3a28f898b5f5ee08b71b4922df70)
+
+Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
+---
+ Lib/plistlib.py | 31 +++++---
+ Lib/test/test_plistlib.py | 37 +++++++++-
+ Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst | 5 +
+ 3 files changed, 59 insertions(+), 14 deletions(-)
+ create mode 100644 Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst
+
+Index: Python-3.6.15/Lib/plistlib.py
+===================================================================
+--- Python-3.6.15.orig/Lib/plistlib.py 2025-12-20 20:02:29.313682401 +0100
++++ Python-3.6.15/Lib/plistlib.py 2025-12-20 20:04:29.519412772 +0100
+@@ -64,6 +64,9 @@
+ from warnings import warn
+ from xml.parsers.expat import ParserCreate
+
++# Data larger than this will be read in chunks, to prevent extreme
++# overallocation.
++_MIN_READ_BUF_SIZE = 1 << 20
+
+ PlistFormat = enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__)
+ globals().update(PlistFormat.__members__)
+@@ -646,12 +649,24 @@
+
+ return tokenL
+
++ def _read(self, size):
++ cursize = min(size, _MIN_READ_BUF_SIZE)
++ data = self._fp.read(cursize)
++ while True:
++ if len(data) != cursize:
++ raise InvalidFileException
++ if cursize == size:
++ return data
++ delta = min(cursize, size - cursize)
++ data += self._fp.read(delta)
++ cursize += delta
++
+ def _read_ints(self, n, size):
+- data = self._fp.read(size * n)
++ data = self._read(size * n)
+ if size in _BINARY_FORMAT:
+ return struct.unpack(f'>{n}{_BINARY_FORMAT[size]}', data)
+ else:
+- if not size or len(data) != size * n:
++ if not size:
+ raise InvalidFileException()
+ return tuple(int.from_bytes(data[i: i + size], 'big')
+ for i in range(0, size * n, size))
+@@ -708,24 +723,18 @@
+
+ elif tokenH == 0x40: # data
+ s = self._get_size(tokenL)
+- result = self._fp.read(s)
+- if len(result) != s:
+- raise InvalidFileException()
++ result = self._read(s)
+ if not self._use_builtin_types:
+ result = Data(result)
+
+ elif tokenH == 0x50: # ascii string
+ s = self._get_size(tokenL)
+- data = self._fp.read(s)
+- if len(data) != s:
+- raise InvalidFileException()
++ data = self._read(s)
+ result = data.decode('ascii')
+
+ elif tokenH == 0x60: # unicode string
+ s = self._get_size(tokenL) * 2
+- data = self._fp.read(s)
+- if len(data) != s:
+- raise InvalidFileException()
++ data = self._read(s)
+ result = data.decode('utf-16be')
+
+ # tokenH == 0x80 is documented as 'UID' and appears to be used for
+Index: Python-3.6.15/Lib/test/test_plistlib.py
+===================================================================
+--- Python-3.6.15.orig/Lib/test/test_plistlib.py 2025-12-20 20:02:29.313682401 +0100
++++ Python-3.6.15/Lib/test/test_plistlib.py 2025-12-20 20:04:29.519870516 +0100
+@@ -745,8 +745,7 @@
+
+ class TestBinaryPlistlib(unittest.TestCase):
+
+- @staticmethod
+- def decode(*objects, offset_size=1, ref_size=1):
++ def build(self, *objects, offset_size=1, ref_size=1):
+ data = [b'bplist00']
+ offset = 8
+ offsets = []
+@@ -758,7 +757,11 @@
+ len(objects), 0, offset)
+ data.extend(offsets)
+ data.append(tail)
+- return plistlib.loads(b''.join(data), fmt=plistlib.FMT_BINARY)
++ return b''.join(data)
++
++ def decode(self, *objects, offset_size=1, ref_size=1):
++ data = self.build(*objects, offset_size=offset_size, ref_size=ref_size)
++ return plistlib.loads(data, fmt=plistlib.FMT_BINARY)
+
+ def test_nonstandard_refs_size(self):
+ # Issue #21538: Refs and offsets are 24-bit integers
+@@ -868,6 +871,34 @@
+ with self.assertRaises(plistlib.InvalidFileException):
+ plistlib.loads(b'bplist00' + data, fmt=plistlib.FMT_BINARY)
+
++ def test_truncated_large_data(self):
++ self.addCleanup(support.unlink, support.TESTFN)
++ def check(data):
++ with open(support.TESTFN, 'wb') as f:
++ f.write(data)
++ # buffered file
++ with open(support.TESTFN, 'rb') as f:
++ with self.assertRaises(plistlib.InvalidFileException):
++ plistlib.load(f, fmt=plistlib.FMT_BINARY)
++ # unbuffered file
++ with open(support.TESTFN, 'rb', buffering=0) as f:
++ with self.assertRaises(plistlib.InvalidFileException):
++ plistlib.load(f, fmt=plistlib.FMT_BINARY)
++ for w in range(20, 64):
++ s = 1 << w
++ # data
++ check(self.build(b'\x4f\x13' + s.to_bytes(8, 'big')))
++ # ascii string
++ check(self.build(b'\x5f\x13' + s.to_bytes(8, 'big')))
++ # unicode string
++ check(self.build(b'\x6f\x13' + s.to_bytes(8, 'big')))
++ # array
++ check(self.build(b'\xaf\x13' + s.to_bytes(8, 'big')))
++ # dict
++ check(self.build(b'\xdf\x13' + s.to_bytes(8, 'big')))
++ # number of objects
++ check(b'bplist00' + struct.pack('>6xBBQQQ', 1, 1, s, 0, 8))
++
+
+ class TestPlistlibDeprecated(unittest.TestCase):
+ def test_io_deprecated(self):
+Index: Python-3.6.15/Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ Python-3.6.15/Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst 2025-12-20 20:04:29.520190112 +0100
+@@ -0,0 +1,5 @@
++Fix a potential memory denial of service in the :mod:`plistlib` module.
++When reading a Plist file received from untrusted source, it could cause
++an arbitrary amount of memory to be allocated.
++This could have led to symptoms including a :exc:`MemoryError`, swapping, out
++of memory (OOM) killed processes or containers, or even system crashes.
diff --git a/python36.changes b/python36.changes
index 23917eb..5f236ad 100644
--- a/python36.changes
+++ b/python36.changes
@@ -1,3 +1,17 @@
+-------------------------------------------------------------------
+Thu Dec 18 10:33:44 UTC 2025 - Matej Cepl <mcepl@cepl.eu>
+
+- Add CVE-2025-13836-http-resp-cont-len.patch (bsc#1254400,
+ CVE-2025-13836) to prevent reading an HTTP response from
+ a server, if no read amount is specified, with using
+ Content-Length per default as the length.
+- Add CVE-2025-12084-minidom-quad-search.patch prevent quadratic
+ behavior in node ID cache clearing (CVE-2025-12084,
+ bsc#1254997).
+- Add CVE-2025-13837-plistlib-mailicious-length.patch protect
+ against OOM when loading malicious content (CVE-2025-13837,
+ bsc#1254401).
+
-------------------------------------------------------------------
Thu Nov 13 23:45:30 UTC 2025 - Matej Cepl <mcepl@suse.com>
diff --git a/python36.spec b/python36.spec
index 6f6dd5e..1a49929 100644
--- a/python36.spec
+++ b/python36.spec
@@ -206,6 +206,15 @@ Patch78: CVE-2025-8291-consistency-zip64.patch
# PATCH-FIX-UPSTREAM CVE-2025-6075-expandvars-perf-degrad.patch bsc#1252974 mcepl@suse.com
# Avoid potential quadratic complexity vulnerabilities in path modules
Patch79: CVE-2025-6075-expandvars-perf-degrad.patch
+# PATCH-FIX-UPSTREAM CVE-2025-13836-http-resp-cont-len.patch bsc#1254400 mcepl@suse.com
+# Avoid loading possibly compromised length of HTTP response
+Patch80: CVE-2025-13836-http-resp-cont-len.patch
+# PATCH-FIX-UPSTREAM CVE-2025-12084-minidom-quad-search.patch bsc#1254997 mcepl@suse.com
+# prevent quadratic behavior in node ID cache clearing
+Patch81: CVE-2025-12084-minidom-quad-search.patch
+# PATCH-FIX-UPSTREAM CVE-2025-13837-plistlib-mailicious-length.patch bsc#1254401 mcepl@suse.com
+# protect against OOM when loading malicious content
+Patch82: CVE-2025-13837-plistlib-mailicious-length.patch
BuildRequires: automake
BuildRequires: fdupes
BuildRequires: gmp-devel
--
2.52.0