diff --git a/SOURCES/00386-cve-2021-28861.patch b/SOURCES/00386-cve-2021-28861.patch
new file mode 100644
index 0000000..080026b
--- /dev/null
+++ b/SOURCES/00386-cve-2021-28861.patch
@@ -0,0 +1,130 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Miss Islington (bot)"
+ <31488909+miss-islington@users.noreply.github.com>
+Date: Wed, 22 Jun 2022 15:05:00 -0700
+Subject: [PATCH] 00386: CVE-2021-28861
+
+Fix an open redirection vulnerability in the `http.server` module when
+an URI path starts with `//` that could produce a 301 Location header
+with a misleading target.  Vulnerability discovered, and logic fix
+proposed, by Hamza Avvan (@hamzaavvan).
+
+Test and comments authored by Gregory P. Smith [Google].
+(cherry picked from commit 4abab6b603dd38bec1168e9a37c40a48ec89508e)
+
+Upstream: https://github.com/python/cpython/pull/93879
+Tracking bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2120642
+
+Co-authored-by: Gregory P. Smith <greg@krypto.org>
+---
+ Lib/http/server.py                            |  7 +++
+ Lib/test/test_httpservers.py                  | 53 ++++++++++++++++++-
+ ...2-06-15-20-09-23.gh-issue-87389.QVaC3f.rst |  3 ++
+ 3 files changed, 61 insertions(+), 2 deletions(-)
+ create mode 100644 Misc/NEWS.d/next/Security/2022-06-15-20-09-23.gh-issue-87389.QVaC3f.rst
+
+diff --git a/Lib/http/server.py b/Lib/http/server.py
+index 60a4dadf03..ce05be13d3 100644
+--- a/Lib/http/server.py
++++ b/Lib/http/server.py
+@@ -323,6 +323,13 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
+             return False
+         self.command, self.path, self.request_version = command, path, version
+ 
++        # gh-87389: The purpose of replacing '//' with '/' is to protect
++        # against open redirect attacks possibly triggered if the path starts
++        # with '//' because http clients treat //path as an absolute URI
++        # without scheme (similar to http://path) rather than a path.
++        if self.path.startswith('//'):
++            self.path = '/' + self.path.lstrip('/')  # Reduce to a single /
++
+         # Examine the headers and look for a Connection directive.
+         try:
+             self.headers = http.client.parse_headers(self.rfile,
+diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
+index 66e937e04b..5a0a7c3f74 100644
+--- a/Lib/test/test_httpservers.py
++++ b/Lib/test/test_httpservers.py
+@@ -324,7 +324,7 @@ class SimpleHTTPServerTestCase(BaseTestCase):
+         pass
+ 
+     def setUp(self):
+-        BaseTestCase.setUp(self)
++        super().setUp()
+         self.cwd = os.getcwd()
+         basetempdir = tempfile.gettempdir()
+         os.chdir(basetempdir)
+@@ -343,7 +343,7 @@ class SimpleHTTPServerTestCase(BaseTestCase):
+             except:
+                 pass
+         finally:
+-            BaseTestCase.tearDown(self)
++            super().tearDown()
+ 
+     def check_status_and_reason(self, response, status, data=None):
+         def close_conn():
+@@ -399,6 +399,55 @@ class SimpleHTTPServerTestCase(BaseTestCase):
+         self.check_status_and_reason(response, HTTPStatus.OK,
+                                      data=support.TESTFN_UNDECODABLE)
+ 
++    def test_get_dir_redirect_location_domain_injection_bug(self):
++        """Ensure //evil.co/..%2f../../X does not put //evil.co/ in Location.
++
++        //netloc/ in a Location header is a redirect to a new host.
++        https://github.com/python/cpython/issues/87389
++
++        This checks that a path resolving to a directory on our server cannot
++        resolve into a redirect to another server.
++        """
++        os.mkdir(os.path.join(self.tempdir, 'existing_directory'))
++        url = f'/python.org/..%2f..%2f..%2f..%2f..%2f../%0a%0d/../{self.tempdir_name}/existing_directory'
++        expected_location = f'{url}/'  # /python.org.../ single slash single prefix, trailing slash
++        # Canonicalizes to /tmp/tempdir_name/existing_directory which does
++        # exist and is a dir, triggering the 301 redirect logic.
++        response = self.request(url)
++        self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
++        location = response.getheader('Location')
++        self.assertEqual(location, expected_location, msg='non-attack failed!')
++
++        # //python.org... multi-slash prefix, no trailing slash
++        attack_url = f'/{url}'
++        response = self.request(attack_url)
++        self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
++        location = response.getheader('Location')
++        self.assertFalse(location.startswith('//'), msg=location)
++        self.assertEqual(location, expected_location,
++                msg='Expected Location header to start with a single / and '
++                'end with a / as this is a directory redirect.')
++
++        # ///python.org... triple-slash prefix, no trailing slash
++        attack3_url = f'//{url}'
++        response = self.request(attack3_url)
++        self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
++        self.assertEqual(response.getheader('Location'), expected_location)
++
++        # If the second word in the http request (Request-URI for the http
++        # method) is a full URI, we don't worry about it, as that'll be parsed
++        # and reassembled as a full URI within BaseHTTPRequestHandler.send_head
++        # so no errant scheme-less //netloc//evil.co/ domain mixup can happen.
++        attack_scheme_netloc_2slash_url = f'https://pypi.org/{url}'
++        expected_scheme_netloc_location = f'{attack_scheme_netloc_2slash_url}/'
++        response = self.request(attack_scheme_netloc_2slash_url)
++        self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
++        location = response.getheader('Location')
++        # We're just ensuring that the scheme and domain make it through, if
++        # there are or aren't multiple slashes at the start of the path that
++        # follows that isn't important in this Location: header.
++        self.assertTrue(location.startswith('https://pypi.org/'), msg=location)
++
+     def test_get(self):
+         #constructs the path relative to the root directory of the HTTPServer
+         response = self.request(self.base_url + '/test')
+diff --git a/Misc/NEWS.d/next/Security/2022-06-15-20-09-23.gh-issue-87389.QVaC3f.rst b/Misc/NEWS.d/next/Security/2022-06-15-20-09-23.gh-issue-87389.QVaC3f.rst
+new file mode 100644
+index 0000000000..029d437190
+--- /dev/null
++++ b/Misc/NEWS.d/next/Security/2022-06-15-20-09-23.gh-issue-87389.QVaC3f.rst
+@@ -0,0 +1,3 @@
++:mod:`http.server`: Fix an open redirection vulnerability in the HTTP server
++when an URI path starts with ``//``.  Vulnerability discovered, and initial
++fix proposed, by Hamza Avvan.
diff --git a/SOURCES/00387-cve-2020-10735-prevent-dos-by-very-large-int.patch b/SOURCES/00387-cve-2020-10735-prevent-dos-by-very-large-int.patch
new file mode 100644
index 0000000..c989a0b
--- /dev/null
+++ b/SOURCES/00387-cve-2020-10735-prevent-dos-by-very-large-int.patch
@@ -0,0 +1,1381 @@
+From ef282220bd6e759c125c82351355d27627a0c08f Mon Sep 17 00:00:00 2001
+From: Victor Stinner <vstinner@python.org>
+Date: Thu, 15 Sep 2022 17:35:24 +0200
+Subject: [PATCH] 00387: CVE-2020-10735: Prevent DoS by very large int()
+
+gh-95778: CVE-2020-10735: Prevent DoS by very large int() (GH-96504)
+
+Converting between `int` and `str` in bases other than 2
+(binary), 4, 8 (octal), 16 (hexadecimal), or 32 such as base 10 (decimal) now
+raises a `ValueError` if the number of digits in string form is above a
+limit to avoid potential denial of service attacks due to the algorithmic
+complexity. This is a mitigation for CVE-2020-10735
+(https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-10735).
+
+This new limit can be configured or disabled by environment variable, command
+line flag, or :mod:`sys` APIs. See the `Integer String Conversion Length
+Limitation` documentation.  The default limit is 4300
+digits in string form.
+
+Patch by Gregory P. Smith [Google] and Christian Heimes [Red Hat] with feedback
+from Victor Stinner, Thomas Wouters, Steve Dower, Ned Deily, and Mark Dickinson.
+
+Notes on the backport to Python 3.6 in RHEL:
+
+* Use "Python 3.6.8-48" version in the documentation, whereas this
+  version will never be released
+* Only add _Py_global_config_int_max_str_digits global variable:
+  Python 3.6 doesn't have PyConfig API (PEP 597) nor _PyRuntime.
+* sys.flags.int_max_str_digits cannot be -1 on Python 3.6: it is
+  set to the default limit. Adapt test_int_max_str_digits() for that.
+* Declare _PY_LONG_DEFAULT_MAX_STR_DIGITS and
+  _PY_LONG_MAX_STR_DIGITS_THRESHOLD macros in longobject.h but only
+  if the Py_BUILD_CORE macro is defined.
+* Declare _Py_global_config_int_max_str_digits in pydebug.h.
+
+(cherry picked from commit 511ca9452033ef95bc7d7fc404b8161068226002)
+
+gh-95778: Mention sys.set_int_max_str_digits() in error message (#96874)
+
+When ValueError is raised if an integer is larger than the limit,
+mention sys.set_int_max_str_digits() in the error message.
+
+(cherry picked from commit e841ffc915e82e5ea6e3b473205417d63494808d)
+
+gh-96848: Fix -X int_max_str_digits option parsing (#96988)
+
+Fix command line parsing: reject "-X int_max_str_digits" option with
+no value (invalid) when the PYTHONINTMAXSTRDIGITS environment
+variable is set to a valid limit.
+
+(cherry picked from commit 41351662bcd21672d8ccfa62fe44d72027e6bcf8)
+---
+ Doc/library/functions.rst         |   8 ++
+ Doc/library/json.rst              |  11 ++
+ Doc/library/stdtypes.rst          | 159 ++++++++++++++++++++++++
+ Doc/library/sys.rst               |  53 ++++++--
+ Doc/library/test.rst              |  10 ++
+ Doc/using/cmdline.rst             |  14 +++
+ Doc/whatsnew/3.6.rst              |  15 +++
+ Include/longobject.h              |  38 ++++++
+ Include/pydebug.h                 |   2 +
+ Lib/test/support/__init__.py      |  10 ++
+ Lib/test/test_ast.py              |   8 ++
+ Lib/test/test_cmd_line.py         |  35 ++++++
+ Lib/test/test_compile.py          |  13 ++
+ Lib/test/test_decimal.py          |  18 +++
+ Lib/test/test_int.py              | 196 ++++++++++++++++++++++++++++++
+ Lib/test/test_json/test_decode.py |   8 ++
+ Lib/test/test_sys.py              |  11 +-
+ Lib/test/test_xmlrpc.py           |  10 ++
+ Modules/main.c                    |   7 ++
+ Objects/longobject.c              | 168 ++++++++++++++++++++++++-
+ Python/ast.c                      |  26 +++-
+ Python/pylifecycle.c              |   2 +
+ Python/sysmodule.c                |  46 ++++++-
+ 23 files changed, 853 insertions(+), 15 deletions(-)
+
+diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
+index bc528dd..b0806b2 100644
+--- a/Doc/library/functions.rst
++++ b/Doc/library/functions.rst
+@@ -748,6 +748,14 @@ are always available.  They are listed here in alphabetical order.
+    .. versionchanged:: 3.6
+       Grouping digits with underscores as in code literals is allowed.
+ 
++   .. versionchanged:: 3.6.8-48
++      :class:`int` string inputs and string representations can be limited to
++      help avoid denial of service attacks. A :exc:`ValueError` is raised when
++      the limit is exceeded while converting a string *x* to an :class:`int` or
++      when converting an :class:`int` into a string would exceed the limit.
++      See the :ref:`integer string conversion length limitation
++      <int_max_str_digits>` documentation.
++
+ 
+ .. function:: isinstance(object, classinfo)
+ 
+diff --git a/Doc/library/json.rst b/Doc/library/json.rst
+index 98ca86e..330e53f 100644
+--- a/Doc/library/json.rst
++++ b/Doc/library/json.rst
+@@ -18,6 +18,11 @@ is a lightweight data interchange format inspired by
+ `JavaScript <https://en.wikipedia.org/wiki/JavaScript>`_ object literal syntax
+ (although it is not a strict subset of JavaScript [#rfc-errata]_ ).
+ 
++.. warning::
++   Be cautious when parsing JSON data from untrusted sources. A malicious
++   JSON string may cause the decoder to consume considerable CPU and memory
++   resources. Limiting the size of data to be parsed is recommended.
++
+ :mod:`json` exposes an API familiar to users of the standard library
+ :mod:`marshal` and :mod:`pickle` modules.
+ 
+@@ -245,6 +250,12 @@ Basic Usage
+    be used to use another datatype or parser for JSON integers
+    (e.g. :class:`float`).
+ 
++   .. versionchanged:: 3.6.8-48
++      The default *parse_int* of :func:`int` now limits the maximum length of
++      the integer string via the interpreter's :ref:`integer string
++      conversion length limitation <int_max_str_digits>` to help avoid denial
++      of service attacks.
++
+    *parse_constant*, if specified, will be called with one of the following
+    strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``.
+    This can be used to raise an exception if invalid JSON numbers
+diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
+index 00e1f4c..1dc3253 100644
+--- a/Doc/library/stdtypes.rst
++++ b/Doc/library/stdtypes.rst
+@@ -4671,6 +4671,165 @@ types, where they are relevant.  Some of these are not reported by the
+       [<class 'bool'>]
+ 
+ 
++.. _int_max_str_digits:
++
++Integer string conversion length limitation
++===========================================
++
++CPython has a global limit for converting between :class:`int` and :class:`str`
++to mitigate denial of service attacks. This limit *only* applies to decimal or
++other non-power-of-two number bases. Hexadecimal, octal, and binary conversions
++are unlimited. The limit can be configured.
++
++The :class:`int` type in CPython is an abitrary length number stored in binary
++form (commonly known as a "bignum"). There exists no algorithm that can convert
++a string to a binary integer or a binary integer to a string in linear time,
++*unless* the base is a power of 2. Even the best known algorithms for base 10
++have sub-quadratic complexity. Converting a large value such as ``int('1' *
++500_000)`` can take over a second on a fast CPU.
++
++Limiting conversion size offers a practical way to avoid `CVE-2020-10735
++<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-10735>`_.
++
++The limit is applied to the number of digit characters in the input or output
++string when a non-linear conversion algorithm would be involved.  Underscores
++and the sign are not counted towards the limit.
++
++When an operation would exceed the limit, a :exc:`ValueError` is raised:
++
++.. doctest::
++
++   >>> import sys
++   >>> sys.set_int_max_str_digits(4300)  # Illustrative, this is the default.
++   >>> _ = int('2' * 5432)
++   Traceback (most recent call last):
++   ...
++   ValueError: Exceeds the limit (4300) for integer string conversion: value has 5432 digits; use sys.set_int_max_str_digits() to increase the limit.
++   >>> i = int('2' * 4300)
++   >>> len(str(i))
++   4300
++   >>> i_squared = i*i
++   >>> len(str(i_squared))
++   Traceback (most recent call last):
++   ...
++   ValueError: Exceeds the limit (4300) for integer string conversion: value has 8599 digits; use sys.set_int_max_str_digits() to increase the limit.
++   >>> len(hex(i_squared))
++   7144
++   >>> assert int(hex(i_squared), base=16) == i*i  # Hexadecimal is unlimited.
++
++The default limit is 4300 digits as provided in
++:data:`sys.int_info.default_max_str_digits <sys.int_info>`.
++The lowest limit that can be configured is 640 digits as provided in
++:data:`sys.int_info.str_digits_check_threshold <sys.int_info>`.
++
++Verification:
++
++.. doctest::
++
++   >>> import sys
++   >>> assert sys.int_info.default_max_str_digits == 4300, sys.int_info
++   >>> assert sys.int_info.str_digits_check_threshold == 640, sys.int_info
++   >>> msg = int('578966293710682886880994035146873798396722250538762761564'
++   ...           '9252925514383915483333812743580549779436104706260696366600'
++   ...           '571186405732').to_bytes(53, 'big')
++   ...
++
++.. versionadded:: 3.6.8-48
++
++Affected APIs
++-------------
++
++The limitation only applies to potentially slow conversions between :class:`int`
++and :class:`str` or :class:`bytes`:
++
++* ``int(string)`` with default base 10.
++* ``int(string, base)`` for all bases that are not a power of 2.
++* ``str(integer)``.
++* ``repr(integer)``
++* any other string conversion to base 10, for example ``f"{integer}"``,
++  ``"{}".format(integer)``, or ``b"%d" % integer``.
++
++The limitations do not apply to functions with a linear algorithm:
++
++* ``int(string, base)`` with base 2, 4, 8, 16, or 32.
++* :func:`int.from_bytes` and :func:`int.to_bytes`.
++* :func:`hex`, :func:`oct`, :func:`bin`.
++* :ref:`formatspec` for hex, octal, and binary numbers.
++* :class:`str` to :class:`float`.
++* :class:`str` to :class:`decimal.Decimal`.
++
++Configuring the limit
++---------------------
++
++Before Python starts up you can use an environment variable or an interpreter
++command line flag to configure the limit:
++
++* :envvar:`PYTHONINTMAXSTRDIGITS`, e.g.
++  ``PYTHONINTMAXSTRDIGITS=640 python3`` to set the limit to 640 or
++  ``PYTHONINTMAXSTRDIGITS=0 python3`` to disable the limitation.
++* :option:`-X int_max_str_digits <-X>`, e.g.
++  ``python3 -X int_max_str_digits=640``
++* :data:`sys.flags.int_max_str_digits` contains the value of
++  :envvar:`PYTHONINTMAXSTRDIGITS` or :option:`-X int_max_str_digits <-X>`.
++  If both the env var and the ``-X`` option are set, the ``-X`` option takes
++  precedence. A value of *-1* indicates that both were unset, thus a value of
++  :data:`sys.int_info.default_max_str_digits` was used during initilization.
++
++From code, you can inspect the current limit and set a new one using these
++:mod:`sys` APIs:
++
++* :func:`sys.get_int_max_str_digits` and :func:`sys.set_int_max_str_digits` are
++  a getter and setter for the interpreter-wide limit. Subinterpreters have
++  their own limit.
++
++Information about the default and minimum can be found in :attr:`sys.int_info`:
++
++* :data:`sys.int_info.default_max_str_digits <sys.int_info>` is the compiled-in
++  default limit.
++* :data:`sys.int_info.str_digits_check_threshold <sys.int_info>` is the lowest
++  accepted value for the limit (other than 0 which disables it).
++
++.. versionadded:: 3.6.8-48
++
++.. caution::
++
++   Setting a low limit *can* lead to problems. While rare, code exists that
++   contains integer constants in decimal in their source that exceed the
++   minimum threshold. A consequence of setting the limit is that Python source
++   code containing decimal integer literals longer than the limit will
++   encounter an error during parsing, usually at startup time or import time or
++   even at installation time - anytime an up to date ``.pyc`` does not already
++   exist for the code. A workaround for source that contains such large
++   constants is to convert them to ``0x`` hexadecimal form as it has no limit.
++
++   Test your application thoroughly if you use a low limit. Ensure your tests
++   run with the limit set early via the environment or flag so that it applies
++   during startup and even during any installation step that may invoke Python
++   to precompile ``.py`` sources to ``.pyc`` files.
++
++Recommended configuration
++-------------------------
++
++The default :data:`sys.int_info.default_max_str_digits` is expected to be
++reasonable for most applications. If your application requires a different
++limit, set it from your main entry point using Python version agnostic code as
++these APIs were added in security patch releases in versions before 3.11.
++
++Example::
++
++   >>> import sys
++   >>> if hasattr(sys, "set_int_max_str_digits"):
++   ...     upper_bound = 68000
++   ...     lower_bound = 4004
++   ...     current_limit = sys.get_int_max_str_digits()
++   ...     if current_limit == 0 or current_limit > upper_bound:
++   ...         sys.set_int_max_str_digits(upper_bound)
++   ...     elif current_limit < lower_bound:
++   ...         sys.set_int_max_str_digits(lower_bound)
++
++If you need to disable it entirely, set it to ``0``.
++
++
+ .. rubric:: Footnotes
+ 
+ .. [1] Additional information on these special methods may be found in the Python
+diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst
+index 9198466..6144f8f 100644
+--- a/Doc/library/sys.rst
++++ b/Doc/library/sys.rst
+@@ -296,6 +296,7 @@ always available.
+    :const:`bytes_warning`        :option:`-b`
+    :const:`quiet`                :option:`-q`
+    :const:`hash_randomization`   :option:`-R`
++   :const:`int_max_str_digits`   :option:`-X int_max_str_digits <-X>` (:ref:`integer string conversion length limitation <int_max_str_digits>`)
+    ============================= =============================
+ 
+    .. versionchanged:: 3.2
+@@ -310,6 +311,9 @@ always available.
+    .. versionchanged:: 3.4
+       Added ``isolated`` attribute for :option:`-I` ``isolated`` flag.
+ 
++   .. versionchanged:: 3.6.8-48
++      Added the ``int_max_str_digits`` attribute.
++
+ .. data:: float_info
+ 
+    A :term:`struct sequence` holding information about the float type. It
+@@ -468,6 +472,15 @@ always available.
+ 
+    .. versionadded:: 3.6
+ 
++
++.. function:: get_int_max_str_digits()
++
++   Returns the current value for the :ref:`integer string conversion length
++   limitation <int_max_str_digits>`. See also :func:`set_int_max_str_digits`.
++
++   .. versionadded:: 3.6.8-48
++
++
+ .. function:: getrefcount(object)
+ 
+    Return the reference count of the *object*.  The count returned is generally one
+@@ -730,19 +743,31 @@ always available.
+ 
+    .. tabularcolumns:: |l|L|
+ 
+-   +-------------------------+----------------------------------------------+
+-   | Attribute               | Explanation                                  |
+-   +=========================+==============================================+
+-   | :const:`bits_per_digit` | number of bits held in each digit.  Python   |
+-   |                         | integers are stored internally in base       |
+-   |                         | ``2**int_info.bits_per_digit``               |
+-   +-------------------------+----------------------------------------------+
+-   | :const:`sizeof_digit`   | size in bytes of the C type used to          |
+-   |                         | represent a digit                            |
+-   +-------------------------+----------------------------------------------+
++   +----------------------------------------+-----------------------------------------------+
++   | Attribute                              | Explanation                                   |
++   +========================================+===============================================+
++   | :const:`bits_per_digit`                | number of bits held in each digit.  Python    |
++   |                                        | integers are stored internally in base        |
++   |                                        | ``2**int_info.bits_per_digit``                |
++   +----------------------------------------+-----------------------------------------------+
++   | :const:`sizeof_digit`                  | size in bytes of the C type used to           |
++   |                                        | represent a digit                             |
++   +----------------------------------------+-----------------------------------------------+
++   | :const:`default_max_str_digits`        | default value for                             |
++   |                                        | :func:`sys.get_int_max_str_digits` when it    |
++   |                                        | is not otherwise explicitly configured.       |
++   +----------------------------------------+-----------------------------------------------+
++   | :const:`str_digits_check_threshold`    | minimum non-zero value for                    |
++   |                                        | :func:`sys.set_int_max_str_digits`,           |
++   |                                        | :envvar:`PYTHONINTMAXSTRDIGITS`, or           |
++   |                                        | :option:`-X int_max_str_digits <-X>`.         |
++   +----------------------------------------+-----------------------------------------------+
+ 
+    .. versionadded:: 3.1
+ 
++   .. versionchanged:: 3.6.8-48
++      Added ``default_max_str_digits`` and ``str_digits_check_threshold``.
++
+ 
+ .. data:: __interactivehook__
+ 
+@@ -1001,6 +1026,14 @@ always available.
+ 
+    Availability: Unix.
+ 
++.. function:: set_int_max_str_digits(n)
++
++   Set the :ref:`integer string conversion length limitation
++   <int_max_str_digits>` used by this interpreter. See also
++   :func:`get_int_max_str_digits`.
++
++   .. versionadded:: 3.6.8-48
++
+ .. function:: setprofile(profilefunc)
+ 
+    .. index::
+diff --git a/Doc/library/test.rst b/Doc/library/test.rst
+index 04d6cd8..5153162 100644
+--- a/Doc/library/test.rst
++++ b/Doc/library/test.rst
+@@ -625,6 +625,16 @@ The :mod:`test.support` module defines the following functions:
+    .. versionadded:: 3.6
+ 
+ 
++.. function:: adjust_int_max_str_digits(max_digits)
++
++   This function returns a context manager that will change the global
++   :func:`sys.set_int_max_str_digits` setting for the duration of the
++   context to allow execution of test code that needs a different limit
++   on the number of digits when converting between an integer and string.
++
++   .. versionadded:: 3.6.8-48
++
++
+ The :mod:`test.support` module defines the following classes:
+ 
+ .. class:: TransientResource(exc, **kwargs)
+diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst
+index 65aa3ad..f5f76c4 100644
+--- a/Doc/using/cmdline.rst
++++ b/Doc/using/cmdline.rst
+@@ -422,6 +422,9 @@ Miscellaneous options
+    * ``-X showalloccount`` to output the total count of allocated objects for
+      each type when the program finishes. This only works when Python was built with
+      ``COUNT_ALLOCS`` defined.
++   * ``-X int_max_str_digits`` configures the :ref:`integer string conversion
++     length limitation <int_max_str_digits>`.  See also
++     :envvar:`PYTHONINTMAXSTRDIGITS`.
+ 
+    It also allows passing arbitrary values and retrieving them through the
+    :data:`sys._xoptions` dictionary.
+@@ -438,6 +441,9 @@ Miscellaneous options
+    .. versionadded:: 3.6
+       The ``-X showalloccount`` option.
+ 
++   .. versionadded:: 3.6.8-48
++      The ``-X int_max_str_digits`` option.
++
+ 
+ Options you shouldn't use
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+@@ -571,6 +577,14 @@ conflict.
+    .. versionadded:: 3.2.3
+ 
+ 
++.. envvar:: PYTHONINTMAXSTRDIGITS
++
++   If this variable is set to an integer, it is used to configure the
++   interpreter's global :ref:`integer string conversion length limitation
++   <int_max_str_digits>`.
++
++   .. versionadded:: 3.6.8-48
++
+ .. envvar:: PYTHONIOENCODING
+ 
+    If this is set before running the interpreter, it overrides the encoding used
+diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst
+index 0095844..d669c5c 100644
+--- a/Doc/whatsnew/3.6.rst
++++ b/Doc/whatsnew/3.6.rst
+@@ -2438,3 +2438,18 @@ In 3.6.7 the :mod:`tokenize` module now implicitly emits a ``NEWLINE`` token
+ when provided with input that does not have a trailing new line.  This behavior
+ now matches what the C tokenizer does internally.
+ (Contributed by Ammar Askar in :issue:`33899`.)
++
++
++Notable security feature in 3.6.8-48
++=====================================
++
++Converting between :class:`int` and :class:`str` in bases other than 2
++(binary), 4, 8 (octal), 16 (hexadecimal), or 32 such as base 10 (decimal)
++now raises a :exc:`ValueError` if the number of digits in string form is
++above a limit to avoid potential denial of service attacks due to the
++algorithmic complexity. This is a mitigation for `CVE-2020-10735
++<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-10735>`_.
++This limit can be configured or disabled by environment variable, command
++line flag, or :mod:`sys` APIs. See the :ref:`integer string conversion
++length limitation <int_max_str_digits>` documentation.  The default limit
++is 4300 digits in string form.
+diff --git a/Include/longobject.h b/Include/longobject.h
+index efd409c..d8a080a 100644
+--- a/Include/longobject.h
++++ b/Include/longobject.h
+@@ -209,6 +209,44 @@ PyAPI_FUNC(long) PyOS_strtol(const char *, char **, int);
+ PyAPI_FUNC(PyObject *) _PyLong_GCD(PyObject *, PyObject *);
+ #endif /* !Py_LIMITED_API */
+ 
++#ifdef Py_BUILD_CORE
++/*
++ * Default int base conversion size limitation: Denial of Service prevention.
++ *
++ * Chosen such that this isn't wildly slow on modern hardware and so that
++ * everyone's existing deployed numpy test suite passes before
++ * https://github.com/numpy/numpy/issues/22098 is widely available.
++ *
++ * $ python -m timeit -s 's = "1"*4300' 'int(s)'
++ * 2000 loops, best of 5: 125 usec per loop
++ * $ python -m timeit -s 's = "1"*4300; v = int(s)' 'str(v)'
++ * 1000 loops, best of 5: 311 usec per loop
++ * (zen2 cloud VM)
++ *
++ * 4300 decimal digits fits a ~14284 bit number.
++ */
++#define _PY_LONG_DEFAULT_MAX_STR_DIGITS 4300
++/*
++ * Threshold for max digits check.  For performance reasons int() and
++ * int.__str__() don't checks values that are smaller than this
++ * threshold.  Acts as a guaranteed minimum size limit for bignums that
++ * applications can expect from CPython.
++ *
++ * % python -m timeit -s 's = "1"*640; v = int(s)' 'str(int(s))'
++ * 20000 loops, best of 5: 12 usec per loop
++ *
++ * "640 digits should be enough for anyone." - gps
++ * fits a ~2126 bit decimal number.
++ */
++#define _PY_LONG_MAX_STR_DIGITS_THRESHOLD 640
++
++#if ((_PY_LONG_DEFAULT_MAX_STR_DIGITS != 0) && \
++   (_PY_LONG_DEFAULT_MAX_STR_DIGITS < _PY_LONG_MAX_STR_DIGITS_THRESHOLD))
++# error "_PY_LONG_DEFAULT_MAX_STR_DIGITS smaller than threshold."
++#endif
++
++#endif /* Py_BUILD_CORE */
++
+ #ifdef __cplusplus
+ }
+ #endif
+diff --git a/Include/pydebug.h b/Include/pydebug.h
+index 6e23a89..657c552 100644
+--- a/Include/pydebug.h
++++ b/Include/pydebug.h
+@@ -28,6 +28,8 @@ PyAPI_DATA(int) Py_IsolatedFlag;
+ PyAPI_DATA(int) Py_LegacyWindowsStdioFlag;
+ #endif
+ 
++PyAPI_DATA(int) _Py_global_config_int_max_str_digits;
++
+ /* this is a wrapper around getenv() that pays attention to
+    Py_IgnoreEnvironmentFlag.  It should be used for getting variables like
+    PYTHONPATH and PYTHONHOME from the environment */
+diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
+index e33096e..99920ac 100644
+--- a/Lib/test/support/__init__.py
++++ b/Lib/test/support/__init__.py
+@@ -2912,3 +2912,13 @@ class FakePath:
+             raise self.path
+         else:
+             return self.path
++
++@contextlib.contextmanager
++def adjust_int_max_str_digits(max_digits):
++    """Temporarily change the integer string conversion length limit."""
++    current = sys.get_int_max_str_digits()
++    try:
++        sys.set_int_max_str_digits(max_digits)
++        yield
++    finally:
++        sys.set_int_max_str_digits(current)
+diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
+index e68d0de..7f2d793 100644
+--- a/Lib/test/test_ast.py
++++ b/Lib/test/test_ast.py
+@@ -571,6 +571,14 @@ class ASTHelpers_Test(unittest.TestCase):
+         exec(code, ns)
+         self.assertIn('sleep', ns)
+ 
++    def test_literal_eval_str_int_limit(self):
++        with support.adjust_int_max_str_digits(4000):
++            ast.literal_eval('3'*4000)  # no error
++            with self.assertRaises(SyntaxError) as err_ctx:
++                ast.literal_eval('3'*4001)
++            self.assertIn('Exceeds the limit ', str(err_ctx.exception))
++            self.assertIn(' Consider hexadecimal ', str(err_ctx.exception))
++
+ 
+ class ASTValidatorTests(unittest.TestCase):
+ 
+diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py
+index 5922ed9..fe456ee 100644
+--- a/Lib/test/test_cmd_line.py
++++ b/Lib/test/test_cmd_line.py
+@@ -502,6 +502,41 @@ class CmdLineTest(unittest.TestCase):
+         self.assertEqual(proc.returncode, 0, proc)
+         self.assertEqual(proc.stdout.strip(), b'0')
+ 
++    def test_int_max_str_digits(self):
++        code = "import sys; print(sys.flags.int_max_str_digits, sys.get_int_max_str_digits())"
++
++        assert_python_failure('-X', 'int_max_str_digits', '-c', code)
++        assert_python_failure('-X', 'int_max_str_digits=foo', '-c', code)
++        assert_python_failure('-X', 'int_max_str_digits=100', '-c', code)
++        assert_python_failure('-X', 'int_max_str_digits', '-c', code,
++                              PYTHONINTMAXSTRDIGITS='4000')
++
++        assert_python_failure('-c', code, PYTHONINTMAXSTRDIGITS='foo')
++        assert_python_failure('-c', code, PYTHONINTMAXSTRDIGITS='100')
++
++        def res2int(res):
++            out = res.out.strip().decode("utf-8")
++            return tuple(int(i) for i in out.split())
++
++        res = assert_python_ok('-c', code)
++        self.assertEqual(res2int(res), (sys.get_int_max_str_digits(), sys.get_int_max_str_digits()))
++        res = assert_python_ok('-X', 'int_max_str_digits=0', '-c', code)
++        self.assertEqual(res2int(res), (0, 0))
++        res = assert_python_ok('-X', 'int_max_str_digits=4000', '-c', code)
++        self.assertEqual(res2int(res), (4000, 4000))
++        res = assert_python_ok('-X', 'int_max_str_digits=100000', '-c', code)
++        self.assertEqual(res2int(res), (100000, 100000))
++
++        res = assert_python_ok('-c', code, PYTHONINTMAXSTRDIGITS='0')
++        self.assertEqual(res2int(res), (0, 0))
++        res = assert_python_ok('-c', code, PYTHONINTMAXSTRDIGITS='4000')
++        self.assertEqual(res2int(res), (4000, 4000))
++        res = assert_python_ok(
++            '-X', 'int_max_str_digits=6000', '-c', code,
++            PYTHONINTMAXSTRDIGITS='4000'
++        )
++        self.assertEqual(res2int(res), (6000, 6000))
++
+ 
+ def test_main():
+     test.support.run_unittest(CmdLineTest)
+diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py
+index 13cc882..00e6468 100644
+--- a/Lib/test/test_compile.py
++++ b/Lib/test/test_compile.py
+@@ -189,6 +189,19 @@ if 1:
+         self.assertEqual(eval("0o777"), 511)
+         self.assertEqual(eval("-0o0000010"), -8)
+ 
++    def test_int_literals_too_long(self):
++        n = 3000
++        source = f"a = 1\nb = 2\nc = {'3'*n}\nd = 4"
++        with support.adjust_int_max_str_digits(n):
++            compile(source, "<long_int_pass>", "exec")  # no errors.
++        with support.adjust_int_max_str_digits(n-1):
++            with self.assertRaises(SyntaxError) as err_ctx:
++                compile(source, "<long_int_fail>", "exec")
++            exc = err_ctx.exception
++            self.assertEqual(exc.lineno, 3)
++            self.assertIn('Exceeds the limit ', str(exc))
++            self.assertIn(' Consider hexadecimal ', str(exc))
++
+     def test_unary_minus(self):
+         # Verify treatment of unary minus on negative numbers SF bug #660455
+         if sys.maxsize == 2147483647:
+diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
+index 8808a67..4459b82 100644
+--- a/Lib/test/test_decimal.py
++++ b/Lib/test/test_decimal.py
+@@ -2442,6 +2442,15 @@ class CUsabilityTest(UsabilityTest):
+ class PyUsabilityTest(UsabilityTest):
+     decimal = P
+ 
++    def setUp(self):
++        super().setUp()
++        self._previous_int_limit = sys.get_int_max_str_digits()
++        sys.set_int_max_str_digits(7000)
++
++    def tearDown(self):
++        sys.set_int_max_str_digits(self._previous_int_limit)
++        super().tearDown()
++
+ class PythonAPItests(unittest.TestCase):
+ 
+     def test_abc(self):
+@@ -4499,6 +4508,15 @@ class CCoverage(Coverage):
+ class PyCoverage(Coverage):
+     decimal = P
+ 
++    def setUp(self):
++        super().setUp()
++        self._previous_int_limit = sys.get_int_max_str_digits()
++        sys.set_int_max_str_digits(7000)
++
++    def tearDown(self):
++        sys.set_int_max_str_digits(self._previous_int_limit)
++        super().tearDown()
++
+ class PyFunctionality(unittest.TestCase):
+     """Extra functionality in decimal.py"""
+ 
+diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py
+index a36076e..6cd9a5e 100644
+--- a/Lib/test/test_int.py
++++ b/Lib/test/test_int.py
+@@ -1,4 +1,5 @@
+ import sys
++import time
+ 
+ import unittest
+ from test import support
+@@ -514,5 +515,200 @@ class IntTestCases(unittest.TestCase):
+         self.assertEqual(int('1_2_3_4_5_6_7', 32), 1144132807)
+ 
+ 
++class IntStrDigitLimitsTests(unittest.TestCase):
++
++    int_class = int  # Override this in subclasses to reuse the suite.
++
++    def setUp(self):
++        super().setUp()
++        self._previous_limit = sys.get_int_max_str_digits()
++        sys.set_int_max_str_digits(2048)
++
++    def tearDown(self):
++        sys.set_int_max_str_digits(self._previous_limit)
++        super().tearDown()
++
++    def test_disabled_limit(self):
++        self.assertGreater(sys.get_int_max_str_digits(), 0)
++        self.assertLess(sys.get_int_max_str_digits(), 20_000)
++        with support.adjust_int_max_str_digits(0):
++            self.assertEqual(sys.get_int_max_str_digits(), 0)
++            i = self.int_class('1' * 20_000)
++            str(i)
++        self.assertGreater(sys.get_int_max_str_digits(), 0)
++
++    def test_max_str_digits_edge_cases(self):
++        """Ignore the +/- sign and space padding."""
++        int_class = self.int_class
++        maxdigits = sys.get_int_max_str_digits()
++
++        int_class('1' * maxdigits)
++        int_class(' ' + '1' * maxdigits)
++        int_class('1' * maxdigits + ' ')
++        int_class('+' + '1' * maxdigits)
++        int_class('-' + '1' * maxdigits)
++        self.assertEqual(len(str(10 ** (maxdigits - 1))), maxdigits)
++
++    def check(self, i, base=None):
++        with self.assertRaises(ValueError):
++            if base is None:
++                self.int_class(i)
++            else:
++                self.int_class(i, base)
++
++    def test_max_str_digits(self):
++        maxdigits = sys.get_int_max_str_digits()
++
++        self.check('1' * (maxdigits + 1))
++        self.check(' ' + '1' * (maxdigits + 1))
++        self.check('1' * (maxdigits + 1) + ' ')
++        self.check('+' + '1' * (maxdigits + 1))
++        self.check('-' + '1' * (maxdigits + 1))
++        self.check('1' * (maxdigits + 1))
++
++        i = 10 ** maxdigits
++        with self.assertRaises(ValueError):
++            str(i)
++
++    def test_denial_of_service_prevented_int_to_str(self):
++        """Regression test: ensure we fail before performing O(N**2) work."""
++        maxdigits = sys.get_int_max_str_digits()
++        assert maxdigits < 50_000, maxdigits  # A test prerequisite.
++        get_time = time.process_time
++        if get_time() <= 0:  # some platforms like WASM lack process_time()
++            get_time = time.monotonic
++
++        huge_int = int(f'0x{"c"*65_000}', base=16)  # 78268 decimal digits.
++        digits = 78_268
++        with support.adjust_int_max_str_digits(digits):
++            start = get_time()
++            huge_decimal = str(huge_int)
++        seconds_to_convert = get_time() - start
++        self.assertEqual(len(huge_decimal), digits)
++        # Ensuring that we chose a slow enough conversion to measure.
++        # It takes 0.1 seconds on a Zen based cloud VM in an opt build.
++        if seconds_to_convert < 0.005:
++            raise unittest.SkipTest('"slow" conversion took only '
++                                    f'{seconds_to_convert} seconds.')
++
++        # We test with the limit almost at the size needed to check performance.
++        # The performant limit check is slightly fuzzy, give it a some room.
++        with support.adjust_int_max_str_digits(int(.995 * digits)):
++            with self.assertRaises(ValueError) as err:
++                start = get_time()
++                str(huge_int)
++            seconds_to_fail_huge = get_time() - start
++        self.assertIn('conversion', str(err.exception))
++        self.assertLess(seconds_to_fail_huge, seconds_to_convert/8)
++
++        # Now we test that a conversion that would take 30x as long also fails
++        # in a similarly fast fashion.
++        extra_huge_int = int(f'0x{"c"*500_000}', base=16)  # 602060 digits.
++        with self.assertRaises(ValueError) as err:
++            start = get_time()
++            # If not limited, 8 seconds said Zen based cloud VM.
++            str(extra_huge_int)
++        seconds_to_fail_extra_huge = get_time() - start
++        self.assertIn('conversion', str(err.exception))
++        self.assertLess(seconds_to_fail_extra_huge, seconds_to_convert/8)
++
++    def test_denial_of_service_prevented_str_to_int(self):
++        """Regression test: ensure we fail before performing O(N**2) work."""
++        maxdigits = sys.get_int_max_str_digits()
++        assert maxdigits < 100_000, maxdigits  # A test prerequisite.
++        get_time = time.process_time
++        if get_time() <= 0:  # some platforms like WASM lack process_time()
++            get_time = time.monotonic
++
++        digits = 133700
++        huge = '8'*digits
++        with support.adjust_int_max_str_digits(digits):
++            start = get_time()
++            int(huge)
++        seconds_to_convert = get_time() - start
++        # Ensuring that we chose a slow enough conversion to measure.
++        # It takes 0.1 seconds on a Zen based cloud VM in an opt build.
++        if seconds_to_convert < 0.005:
++            raise unittest.SkipTest('"slow" conversion took only '
++                                    f'{seconds_to_convert} seconds.')
++
++        with support.adjust_int_max_str_digits(digits - 1):
++            with self.assertRaises(ValueError) as err:
++                start = get_time()
++                int(huge)
++            seconds_to_fail_huge = get_time() - start
++        self.assertIn('conversion', str(err.exception))
++        self.assertLess(seconds_to_fail_huge, seconds_to_convert/8)
++
++        # Now we test that a conversion that would take 30x as long also fails
++        # in a similarly fast fashion.
++        extra_huge = '7'*1_200_000
++        with self.assertRaises(ValueError) as err:
++            start = get_time()
++            # If not limited, 8 seconds in the Zen based cloud VM.
++            int(extra_huge)
++        seconds_to_fail_extra_huge = get_time() - start
++        self.assertIn('conversion', str(err.exception))
++        self.assertLess(seconds_to_fail_extra_huge, seconds_to_convert/8)
++
++    def test_power_of_two_bases_unlimited(self):
++        """The limit does not apply to power of 2 bases."""
++        maxdigits = sys.get_int_max_str_digits()
++
++        for base in (2, 4, 8, 16, 32):
++            with self.subTest(base=base):
++                self.int_class('1' * (maxdigits + 1), base)
++                assert maxdigits < 100_000
++                self.int_class('1' * 100_000, base)
++
++    def test_underscores_ignored(self):
++        maxdigits = sys.get_int_max_str_digits()
++
++        triples = maxdigits // 3
++        s = '111' * triples
++        s_ = '1_11' * triples
++        self.int_class(s)  # succeeds
++        self.int_class(s_)  # succeeds
++        self.check(f'{s}111')
++        self.check(f'{s_}_111')
++
++    def test_sign_not_counted(self):
++        int_class = self.int_class
++        max_digits = sys.get_int_max_str_digits()
++        s = '5' * max_digits
++        i = int_class(s)
++        pos_i = int_class(f'+{s}')
++        assert i == pos_i
++        neg_i = int_class(f'-{s}')
++        assert -pos_i == neg_i
++        str(pos_i)
++        str(neg_i)
++
++    def _other_base_helper(self, base):
++        int_class = self.int_class
++        max_digits = sys.get_int_max_str_digits()
++        s = '2' * max_digits
++        i = int_class(s, base)
++        if base > 10:
++            with self.assertRaises(ValueError):
++                str(i)
++        elif base < 10:
++            str(i)
++        with self.assertRaises(ValueError) as err:
++            int_class(f'{s}1', base)
++
++    def test_int_from_other_bases(self):
++        base = 3
++        with self.subTest(base=base):
++            self._other_base_helper(base)
++        base = 36
++        with self.subTest(base=base):
++            self._other_base_helper(base)
++
++
++class IntSubclassStrDigitLimitsTests(IntStrDigitLimitsTests):
++    int_class = IntSubclass
++
++
+ if __name__ == "__main__":
+     unittest.main()
+diff --git a/Lib/test/test_json/test_decode.py b/Lib/test/test_json/test_decode.py
+index 738f109..b5fd4f2 100644
+--- a/Lib/test/test_json/test_decode.py
++++ b/Lib/test/test_json/test_decode.py
+@@ -2,6 +2,7 @@ import decimal
+ from io import StringIO, BytesIO
+ from collections import OrderedDict
+ from test.test_json import PyTest, CTest
++from test import support
+ 
+ 
+ class TestDecode:
+@@ -95,5 +96,12 @@ class TestDecode:
+         d = self.json.JSONDecoder()
+         self.assertRaises(ValueError, d.raw_decode, 'a'*42, -50000)
+ 
++    def test_limit_int(self):
++        maxdigits = 5000
++        with support.adjust_int_max_str_digits(maxdigits):
++            self.loads('1' * maxdigits)
++            with self.assertRaises(ValueError):
++                self.loads('1' * (maxdigits + 1))
++
+ class TestPyDecode(TestDecode, PyTest): pass
+ class TestCDecode(TestDecode, CTest): pass
+diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
+index b41239a..f2b9e08 100644
+--- a/Lib/test/test_sys.py
++++ b/Lib/test/test_sys.py
+@@ -444,11 +444,17 @@ class SysModuleTest(unittest.TestCase):
+         self.assertIsInstance(sys.executable, str)
+         self.assertEqual(len(sys.float_info), 11)
+         self.assertEqual(sys.float_info.radix, 2)
+-        self.assertEqual(len(sys.int_info), 2)
++        self.assertEqual(len(sys.int_info), 4)
+         self.assertTrue(sys.int_info.bits_per_digit % 5 == 0)
+         self.assertTrue(sys.int_info.sizeof_digit >= 1)
++        self.assertGreaterEqual(sys.int_info.default_max_str_digits, 500)
++        self.assertGreaterEqual(sys.int_info.str_digits_check_threshold, 100)
++        self.assertGreater(sys.int_info.default_max_str_digits,
++                           sys.int_info.str_digits_check_threshold)
+         self.assertEqual(type(sys.int_info.bits_per_digit), int)
+         self.assertEqual(type(sys.int_info.sizeof_digit), int)
++        self.assertIsInstance(sys.int_info.default_max_str_digits, int)
++        self.assertIsInstance(sys.int_info.str_digits_check_threshold, int)
+         self.assertIsInstance(sys.hexversion, int)
+ 
+         self.assertEqual(len(sys.hash_info), 9)
+@@ -552,7 +558,8 @@ class SysModuleTest(unittest.TestCase):
+         attrs = ("debug",
+                  "inspect", "interactive", "optimize", "dont_write_bytecode",
+                  "no_user_site", "no_site", "ignore_environment", "verbose",
+-                 "bytes_warning", "quiet", "hash_randomization", "isolated")
++                 "bytes_warning", "quiet", "hash_randomization", "isolated",
++                 "int_max_str_digits")
+         for attr in attrs:
+             self.assertTrue(hasattr(sys.flags, attr), attr)
+             self.assertEqual(type(getattr(sys.flags, attr)), int, attr)
+diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py
+index fc601d4..58553dd 100644
+--- a/Lib/test/test_xmlrpc.py
++++ b/Lib/test/test_xmlrpc.py
+@@ -286,6 +286,16 @@ class XMLRPCTestCase(unittest.TestCase):
+         check('<bigdecimal>9876543210.0123456789</bigdecimal>',
+               decimal.Decimal('9876543210.0123456789'))
+ 
++    def test_limit_int(self):
++        check = self.check_loads
++        maxdigits = 5000
++        with support.adjust_int_max_str_digits(maxdigits):
++            s = '1' * (maxdigits + 1)
++            with self.assertRaises(ValueError):
++                check(f'<int>{s}</int>', None)
++            with self.assertRaises(ValueError):
++                check(f'<biginteger>{s}</biginteger>', None)
++
+     def test_get_host_info(self):
+         # see bug #3613, this raised a TypeError
+         transp = xmlrpc.client.Transport()
+diff --git a/Modules/main.c b/Modules/main.c
+index 96d8be4..405e883 100644
+--- a/Modules/main.c
++++ b/Modules/main.c
+@@ -84,6 +84,9 @@ static const char usage_3[] = "\
+          also PYTHONWARNINGS=arg\n\
+ -x     : skip first line of source, allowing use of non-Unix forms of #!cmd\n\
+ -X opt : set implementation-specific option\n\
++-X int_max_str_digits=number: limit the size of int<->str conversions.\n\
++    This helps avoid denial of service attacks when parsing untrusted data.\n\
++    The default is sys.int_info.default_max_str_digits.  0 disables.\n\
+ ";
+ static const char usage_4[] = "\
+ file   : program read from script file\n\
+@@ -105,6 +108,10 @@ static const char usage_6[] =
+ "   to seed the hashes of str, bytes and datetime objects.  It can also be\n"
+ "   set to an integer in the range [0,4294967295] to get hash values with a\n"
+ "   predictable seed.\n"
++"PYTHONINTMAXSTRDIGITS: limits the maximum digit characters in an int value\n"
++"   when converting from a string and when converting an int back to a str.\n"
++"   A value of 0 disables the limit.  Conversions to or from bases 2, 4, 8,\n"
++"   16, and 32 are never limited.\n"
+ "PYTHONMALLOC: set the Python memory allocators and/or install debug hooks\n"
+ "   on Python memory allocators. Use PYTHONMALLOC=debug to install debug\n"
+ "   hooks.\n"
+diff --git a/Objects/longobject.c b/Objects/longobject.c
+index 3864cec..ea01169 100644
+--- a/Objects/longobject.c
++++ b/Objects/longobject.c
+@@ -33,6 +33,9 @@ static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
+ Py_ssize_t quick_int_allocs, quick_neg_int_allocs;
+ #endif
+ 
++#define _MAX_STR_DIGITS_ERROR_FMT_TO_INT "Exceeds the limit (%d) for integer string conversion: value has %zd digits; use sys.set_int_max_str_digits() to increase the limit"
++#define _MAX_STR_DIGITS_ERROR_FMT_TO_STR "Exceeds the limit (%d) for integer string conversion; use sys.set_int_max_str_digits() to increase the limit"
++
+ static PyObject *
+ get_small_int(sdigit ival)
+ {
+@@ -1593,6 +1596,22 @@ long_to_decimal_string_internal(PyObject *aa,
+     size_a = Py_ABS(Py_SIZE(a));
+     negative = Py_SIZE(a) < 0;
+ 
++    /* quick and dirty pre-check for overflowing the decimal digit limit,
++       based on the inequality 10/3 >= log2(10)
++
++       explanation in https://github.com/python/cpython/pull/96537
++    */
++    if (size_a >= 10 * _PY_LONG_MAX_STR_DIGITS_THRESHOLD
++                  / (3 * PyLong_SHIFT) + 2) {
++        int max_str_digits = _Py_global_config_int_max_str_digits ;
++        if ((max_str_digits > 0) &&
++            (max_str_digits / (3 * PyLong_SHIFT) <= (size_a - 11) / 10)) {
++            PyErr_Format(PyExc_ValueError, _MAX_STR_DIGITS_ERROR_FMT_TO_STR,
++                         max_str_digits);
++            return -1;
++        }
++    }
++
+     /* quick and dirty upper bound for the number of digits
+        required to express a in base _PyLong_DECIMAL_BASE:
+ 
+@@ -1652,6 +1671,16 @@ long_to_decimal_string_internal(PyObject *aa,
+         tenpow *= 10;
+         strlen++;
+     }
++    if (strlen > _PY_LONG_MAX_STR_DIGITS_THRESHOLD) {
++        int max_str_digits = _Py_global_config_int_max_str_digits ;
++        Py_ssize_t strlen_nosign = strlen - negative;
++        if ((max_str_digits > 0) && (strlen_nosign > max_str_digits)) {
++            Py_DECREF(scratch);
++            PyErr_Format(PyExc_ValueError, _MAX_STR_DIGITS_ERROR_FMT_TO_STR,
++                         max_str_digits);
++            return -1;
++        }
++    }
+     if (writer) {
+         if (_PyUnicodeWriter_Prepare(writer, strlen, '9') == -1) {
+             Py_DECREF(scratch);
+@@ -2166,6 +2195,7 @@ PyLong_FromString(const char *str, char **pend, int base)
+ 
+     start = str;
+     if ((base & (base - 1)) == 0) {
++        /* binary bases are not limited by int_max_str_digits */
+         int res = long_from_binary_base(&str, base, &z);
+         if (res < 0) {
+             /* Syntax error. */
+@@ -2318,6 +2348,16 @@ digit beyond the first.
+             goto onError;
+         }
+ 
++        /* Limit the size to avoid excessive computation attacks. */
++        if (digits > _PY_LONG_MAX_STR_DIGITS_THRESHOLD) {
++            int max_str_digits = _Py_global_config_int_max_str_digits ;
++            if ((max_str_digits > 0) && (digits > max_str_digits)) {
++                PyErr_Format(PyExc_ValueError, _MAX_STR_DIGITS_ERROR_FMT_TO_INT,
++                             max_str_digits, digits);
++                return NULL;
++            }
++        }
++
+         /* Create an int object that can contain the largest possible
+          * integer with this base and length.  Note that there's no
+          * need to initialize z->ob_digit -- no slot is read up before
+@@ -4820,6 +4860,7 @@ long_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+         }
+         return PyLong_FromLong(0L);
+     }
++    /* default base and limit, forward to standard implementation */
+     if (obase == NULL)
+         return PyNumber_Long(x);
+ 
+@@ -5482,6 +5523,8 @@ internal representation of integers.  The attributes are read only.");
+ static PyStructSequence_Field int_info_fields[] = {
+     {"bits_per_digit", "size of a digit in bits"},
+     {"sizeof_digit", "size in bytes of the C type used to represent a digit"},
++    {"default_max_str_digits", "maximum string conversion digits limitation"},
++    {"str_digits_check_threshold", "minimum positive value for int_max_str_digits"},
+     {NULL, NULL}
+ };
+ 
+@@ -5489,7 +5532,7 @@ static PyStructSequence_Desc int_info_desc = {
+     "sys.int_info",   /* name */
+     int_info__doc__,  /* doc */
+     int_info_fields,  /* fields */
+-    2                 /* number of fields */
++    4                 /* number of fields */
+ };
+ 
+ PyObject *
+@@ -5504,6 +5547,17 @@ PyLong_GetInfo(void)
+                               PyLong_FromLong(PyLong_SHIFT));
+     PyStructSequence_SET_ITEM(int_info, field++,
+                               PyLong_FromLong(sizeof(digit)));
++    /*
++     * The following two fields were added after investigating uses of
++     * sys.int_info in the wild: Exceedingly rarely used. The ONLY use found was
++     * numba using sys.int_info.bits_per_digit as attribute access rather than
++     * sequence unpacking. Cython and sympy also refer to sys.int_info but only
++     * as info for debugging. No concern about adding these in a backport.
++     */
++    PyStructSequence_SET_ITEM(int_info, field++,
++                              PyLong_FromLong(_PY_LONG_DEFAULT_MAX_STR_DIGITS));
++    PyStructSequence_SET_ITEM(int_info, field++,
++                              PyLong_FromLong(_PY_LONG_MAX_STR_DIGITS_THRESHOLD));
+     if (PyErr_Occurred()) {
+         Py_CLEAR(int_info);
+         return NULL;
+@@ -5511,6 +5565,116 @@ PyLong_GetInfo(void)
+     return int_info;
+ }
+ 
++
++static int
++pymain_str_to_int(const char *str, int *result)
++{
++    errno = 0;
++    const char *endptr = str;
++    long value = strtol(str, (char **)&endptr, 10);
++    if (*endptr != '\0' || errno == ERANGE) {
++        return -1;
++    }
++    if (value < INT_MIN || value > INT_MAX) {
++        return -1;
++    }
++
++    *result = (int)value;
++    return 0;
++}
++
++
++static int
++long_get_max_str_digits_xoption(int *pmaxdigits)
++{
++    PyObject *xoptions = PySys_GetXOptions();
++    if (xoptions == NULL) {
++        return -1;
++    }
++
++    PyObject *key = PyUnicode_FromString("int_max_str_digits");
++    if (key == NULL) {
++        return -1;
++    }
++
++    PyObject *value = PyDict_GetItemWithError(xoptions, key); /* borrowed */
++    Py_DECREF(key);
++    if (value == NULL) {
++        if (PyErr_Occurred()) {
++            return -1;
++        }
++        return 0;
++    }
++
++    if (!PyUnicode_Check(value)) {
++        return -1;
++    }
++
++    PyObject *valuelong = PyLong_FromUnicodeObject(value, 10);
++    if (valuelong == NULL) {
++        return -1;
++    }
++
++    int maxdigits = _PyLong_AsInt(valuelong);
++    Py_DECREF(valuelong);
++    if (maxdigits == -1 && PyErr_Occurred()) {
++        return -1;
++    }
++
++    *pmaxdigits = maxdigits;
++    return 1;
++}
++
++
++static void
++long_init_max_str_digits(void)
++{
++    // PYTHONINTMAXSTRDIGITS env var
++    char *opt = Py_GETENV("PYTHONINTMAXSTRDIGITS");
++    int maxdigits;
++    if (opt) {
++        int valid = 0;
++        if (!pymain_str_to_int(opt, &maxdigits)) {
++            valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD));
++        }
++        if (!valid) {
++#define STRINGIFY(VAL) _STRINGIFY(VAL)
++#define _STRINGIFY(VAL) #VAL
++            fprintf(stderr, "Error in PYTHONINTMAXSTRDIGITS: "
++                    "invalid limit; must be >= "
++                    STRINGIFY(_PY_LONG_MAX_STR_DIGITS_THRESHOLD)
++                    " or 0 for unlimited.\n");
++            exit(1);
++        }
++        _Py_global_config_int_max_str_digits = maxdigits;
++    }
++
++    // -X int_max_str_digits command line option
++    int res = long_get_max_str_digits_xoption(&maxdigits);
++    if (res == 1) {
++        int valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD));
++        if (!valid) {
++            res = -1;
++        }
++    }
++    if (res < 0) {
++        fprintf(stderr, "Error in -X int_max_str_digits: "
++                "invalid limit; must be >= "
++                STRINGIFY(_PY_LONG_MAX_STR_DIGITS_THRESHOLD)
++                " or 0 for unlimited.\n");
++        exit(1);
++    }
++    if (res == 1) {
++        _Py_global_config_int_max_str_digits = maxdigits;
++    }
++
++    // Default value
++    if (_Py_global_config_int_max_str_digits == -1) {
++        _Py_global_config_int_max_str_digits = _PY_LONG_DEFAULT_MAX_STR_DIGITS;
++    }
++}
++
++
+ int
+ _PyLong_Init(void)
+ {
+@@ -5549,6 +5713,8 @@ _PyLong_Init(void)
+             return 0;
+     }
+ 
++    long_init_max_str_digits();
++
+     return 1;
+ }
+ 
+diff --git a/Python/ast.c b/Python/ast.c
+index 675063e..4b69d86 100644
+--- a/Python/ast.c
++++ b/Python/ast.c
+@@ -2149,8 +2149,32 @@ ast_for_atom(struct compiling *c, const node *n)
+     }
+     case NUMBER: {
+         PyObject *pynum = parsenumber(c, STR(ch));
+-        if (!pynum)
++        if (!pynum) {
++            PyThreadState *tstate = PyThreadState_GET();
++            // The only way a ValueError should happen in _this_ code is via
++            // PyLong_FromString hitting a length limit.
++            if (tstate->curexc_type == PyExc_ValueError &&
++                tstate->curexc_value != NULL) {
++                PyObject *type, *value, *tb;
++                // This acts as PyErr_Clear() as we're replacing curexc.
++                PyErr_Fetch(&type, &value, &tb);
++                Py_XDECREF(tb);
++                Py_DECREF(type);
++                PyObject *helpful_msg = PyUnicode_FromFormat(
++                    "%S - Consider hexadecimal for huge integer literals "
++                    "to avoid decimal conversion limits.",
++                    value);
++                if (helpful_msg) {
++                    const char* error_msg = PyUnicode_AsUTF8(helpful_msg);
++                    if (error_msg) {
++                        ast_error(c, ch, error_msg);
++                    }
++                    Py_DECREF(helpful_msg);
++                }
++                Py_DECREF(value);
++            }
+             return NULL;
++        }
+ 
+         if (PyArena_AddPyObject(c->c_arena, pynum) < 0) {
+             Py_DECREF(pynum);
+diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
+index 0b985bf..095d1ef 100644
+--- a/Python/pylifecycle.c
++++ b/Python/pylifecycle.c
+@@ -97,6 +97,8 @@ int Py_IsolatedFlag = 0; /* for -I, isolate from user's env */
+ int Py_LegacyWindowsFSEncodingFlag = 0; /* Uses mbcs instead of utf-8 */
+ int Py_LegacyWindowsStdioFlag = 0; /* Uses FileIO instead of WindowsConsoleIO */
+ #endif
++/* Unusual name compared to the above for backporting from 3.12 reasons. */
++int _Py_global_config_int_max_str_digits = -1; /* -X int_max_str_digits or PYTHONINTMAXSTRDIGITS */
+ 
+ PyThreadState *_Py_Finalizing = NULL;
+ 
+diff --git a/Python/sysmodule.c b/Python/sysmodule.c
+index 7d1493c..ecdb62c 100644
+--- a/Python/sysmodule.c
++++ b/Python/sysmodule.c
+@@ -1079,6 +1079,46 @@ sys_mdebug(PyObject *self, PyObject *args)
+ }
+ #endif /* USE_MALLOPT */
+ 
++static PyObject *
++sys_get_int_max_str_digits(PyObject *module, PyObject *Py_UNUSED(ignored))
++{
++    return PyLong_FromSsize_t(_Py_global_config_int_max_str_digits);
++}
++
++PyDoc_STRVAR(sys_get_int_max_str_digits__doc__,
++"get_int_max_str_digits($module, /)\n"
++"--\n"
++"\n"
++"Set the maximum string digits limit for non-binary int<->str conversions.");
++
++static PyObject *
++sys_set_int_max_str_digits(PyObject *module, PyObject *args, PyObject *kwds)
++{
++    static char *kwlist[] = {"maxdigits", NULL};
++    int maxdigits;
++
++    if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:set_int_max_str_digits",
++                                     kwlist, &maxdigits))
++        return NULL;
++
++    if ((!maxdigits) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)) {
++        _Py_global_config_int_max_str_digits = maxdigits;
++        Py_RETURN_NONE;
++    } else {
++        PyErr_Format(
++            PyExc_ValueError, "maxdigits must be 0 or larger than %d",
++            _PY_LONG_MAX_STR_DIGITS_THRESHOLD);
++        return NULL;
++    }
++}
++
++PyDoc_STRVAR(sys_set_int_max_str_digits__doc__,
++"set_int_max_str_digits($module, /, maxdigits)\n"
++"--\n"
++"\n"
++"Set the maximum string digits limit for non-binary int<->str conversions.");
++
++
+ size_t
+ _PySys_GetSizeOf(PyObject *o)
+ {
+@@ -1434,6 +1474,8 @@ static PyMethodDef sys_methods[] = {
+      METH_VARARGS | METH_KEYWORDS, set_asyncgen_hooks_doc},
+     {"get_asyncgen_hooks", sys_get_asyncgen_hooks, METH_NOARGS,
+      get_asyncgen_hooks_doc},
++    {"get_int_max_str_digits", sys_get_int_max_str_digits, METH_NOARGS, sys_get_int_max_str_digits__doc__},
++    {"set_int_max_str_digits", (PyCFunction)sys_set_int_max_str_digits, METH_VARARGS|METH_KEYWORDS, sys_set_int_max_str_digits__doc__},
+     {NULL,              NULL}           /* sentinel */
+ };
+ 
+@@ -1681,6 +1723,7 @@ static PyStructSequence_Field flags_fields[] = {
+     {"quiet",                   "-q"},
+     {"hash_randomization",      "-R"},
+     {"isolated",                "-I"},
++    {"int_max_str_digits",      "-X int_max_str_digits"},
+     {0}
+ };
+ 
+@@ -1688,7 +1731,7 @@ static PyStructSequence_Desc flags_desc = {
+     "sys.flags",        /* name */
+     flags__doc__,       /* doc */
+     flags_fields,       /* fields */
+-    13
++    14
+ };
+ 
+ static PyObject*
+@@ -1719,6 +1762,7 @@ make_flags(void)
+     SetFlag(Py_QuietFlag);
+     SetFlag(Py_HashRandomizationFlag);
+     SetFlag(Py_IsolatedFlag);
++    SetFlag(_Py_global_config_int_max_str_digits);
+ #undef SetFlag
+ 
+     if (PyErr_Occurred()) {
+-- 
+2.37.3
+
diff --git a/SOURCES/00394-cve-2022-45061-cpu-denial-of-service-via-inefficient-idna-decoder.patch b/SOURCES/00394-cve-2022-45061-cpu-denial-of-service-via-inefficient-idna-decoder.patch
new file mode 100644
index 0000000..2eb1aa0
--- /dev/null
+++ b/SOURCES/00394-cve-2022-45061-cpu-denial-of-service-via-inefficient-idna-decoder.patch
@@ -0,0 +1,95 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Miss Islington (bot)"
+ <31488909+miss-islington@users.noreply.github.com>
+Date: Mon, 7 Nov 2022 19:22:14 -0800
+Subject: [PATCH] 00394: CVE-2022-45061: CPU denial of service via inefficient
+ IDNA decoder
+
+gh-98433: Fix quadratic time idna decoding.
+
+There was an unnecessary quadratic loop in idna decoding. This restores
+the behavior to linear.
+
+(cherry picked from commit a6f6c3a3d6f2b580f2d87885c9b8a9350ad7bf15)
+
+Co-authored-by: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
+Co-authored-by: Gregory P. Smith <greg@krypto.org>
+---
+ Lib/encodings/idna.py                         | 32 +++++++++----------
+ Lib/test/test_codecs.py                       |  6 ++++
+ ...2-11-04-09-29-36.gh-issue-98433.l76c5G.rst |  6 ++++
+ 3 files changed, 27 insertions(+), 17 deletions(-)
+ create mode 100644 Misc/NEWS.d/next/Security/2022-11-04-09-29-36.gh-issue-98433.l76c5G.rst
+
+diff --git a/Lib/encodings/idna.py b/Lib/encodings/idna.py
+index ea4058512f..bf98f51336 100644
+--- a/Lib/encodings/idna.py
++++ b/Lib/encodings/idna.py
+@@ -39,23 +39,21 @@ def nameprep(label):
+ 
+     # Check bidi
+     RandAL = [stringprep.in_table_d1(x) for x in label]
+-    for c in RandAL:
+-        if c:
+-            # There is a RandAL char in the string. Must perform further
+-            # tests:
+-            # 1) The characters in section 5.8 MUST be prohibited.
+-            # This is table C.8, which was already checked
+-            # 2) If a string contains any RandALCat character, the string
+-            # MUST NOT contain any LCat character.
+-            if any(stringprep.in_table_d2(x) for x in label):
+-                raise UnicodeError("Violation of BIDI requirement 2")
+-
+-            # 3) If a string contains any RandALCat character, a
+-            # RandALCat character MUST be the first character of the
+-            # string, and a RandALCat character MUST be the last
+-            # character of the string.
+-            if not RandAL[0] or not RandAL[-1]:
+-                raise UnicodeError("Violation of BIDI requirement 3")
++    if any(RandAL):
++        # There is a RandAL char in the string. Must perform further
++        # tests:
++        # 1) The characters in section 5.8 MUST be prohibited.
++        # This is table C.8, which was already checked
++        # 2) If a string contains any RandALCat character, the string
++        # MUST NOT contain any LCat character.
++        if any(stringprep.in_table_d2(x) for x in label):
++            raise UnicodeError("Violation of BIDI requirement 2")
++        # 3) If a string contains any RandALCat character, a
++        # RandALCat character MUST be the first character of the
++        # string, and a RandALCat character MUST be the last
++        # character of the string.
++        if not RandAL[0] or not RandAL[-1]:
++            raise UnicodeError("Violation of BIDI requirement 3")
+ 
+     return label
+ 
+diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py
+index 56485de3f6..a798d1f287 100644
+--- a/Lib/test/test_codecs.py
++++ b/Lib/test/test_codecs.py
+@@ -1640,6 +1640,12 @@ class IDNACodecTest(unittest.TestCase):
+         self.assertEqual("pyth\xf6n.org".encode("idna"), b"xn--pythn-mua.org")
+         self.assertEqual("pyth\xf6n.org.".encode("idna"), b"xn--pythn-mua.org.")
+ 
++    def test_builtin_decode_length_limit(self):
++        with self.assertRaisesRegex(UnicodeError, "too long"):
++            (b"xn--016c"+b"a"*1100).decode("idna")
++        with self.assertRaisesRegex(UnicodeError, "too long"):
++            (b"xn--016c"+b"a"*70).decode("idna")
++
+     def test_stream(self):
+         r = codecs.getreader("idna")(io.BytesIO(b"abc"))
+         r.read(3)
+diff --git a/Misc/NEWS.d/next/Security/2022-11-04-09-29-36.gh-issue-98433.l76c5G.rst b/Misc/NEWS.d/next/Security/2022-11-04-09-29-36.gh-issue-98433.l76c5G.rst
+new file mode 100644
+index 0000000000..5185fac2e2
+--- /dev/null
++++ b/Misc/NEWS.d/next/Security/2022-11-04-09-29-36.gh-issue-98433.l76c5G.rst
+@@ -0,0 +1,6 @@
++The IDNA codec decoder used on DNS hostnames by :mod:`socket` or :mod:`asyncio`
++related name resolution functions no longer involves a quadratic algorithm.
++This prevents a potential CPU denial of service if an out-of-spec excessive
++length hostname involving bidirectional characters were decoded. Some protocols
++such as :mod:`urllib` http ``3xx`` redirects potentially allow for an attacker
++to supply such a name.
diff --git a/SPECS/python3.spec b/SPECS/python3.spec
index 4937f99..cd2dd36 100644
--- a/SPECS/python3.spec
+++ b/SPECS/python3.spec
@@ -14,7 +14,7 @@ URL: https://www.python.org/
 #  WARNING  When rebasing to a new Python version,
 #           remember to update the python3-docs package as well
 Version: %{pybasever}.8
-Release: 48%{?dist}
+Release: 48%{?dist}.1
 License: Python
 
 
@@ -695,6 +695,76 @@ Patch378: 00378-support-expat-2-4-5.patch
 # Tracker bug: https://bugzilla.redhat.com/show_bug.cgi?id=2075390
 Patch382: 00382-cve-2015-20107.patch
 
+# 00386 #
+# CVE-2021-28861
+#
+# Fix an open redirection vulnerability in the `http.server` module when
+# an URI path starts with `//` that could produce a 301 Location header
+# with a misleading target.  Vulnerability discovered, and logic fix
+# proposed, by Hamza Avvan (@hamzaavvan).
+#
+# Test and comments authored by Gregory P. Smith [Google].
+#
+# Upstream: https://github.com/python/cpython/pull/93879
+# Tracking bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2120642
+Patch386: 00386-cve-2021-28861.patch
+
+# 00387 #
+# CVE-2020-10735: Prevent DoS by very large int()
+#
+# gh-95778: CVE-2020-10735: Prevent DoS by very large int() (GH-96504)
+#
+# Converting between `int` and `str` in bases other than 2
+# (binary), 4, 8 (octal), 16 (hexadecimal), or 32 such as base 10 (decimal) now
+# raises a `ValueError` if the number of digits in string form is above a
+# limit to avoid potential denial of service attacks due to the algorithmic
+# complexity. This is a mitigation for CVE-2020-10735
+# (https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-10735).
+#
+# This new limit can be configured or disabled by environment variable, command
+# line flag, or :mod:`sys` APIs. See the `Integer String Conversion Length
+# Limitation` documentation.  The default limit is 4300
+# digits in string form.
+#
+# Patch by Gregory P. Smith [Google] and Christian Heimes [Red Hat] with feedback
+# from Victor Stinner, Thomas Wouters, Steve Dower, Ned Deily, and Mark Dickinson.
+#
+# Notes on the backport to Python 3.6 in RHEL:
+#
+# * Use "Python 3.6.8-48" version in the documentation, whereas this
+#   version will never be released
+# * Only add _Py_global_config_int_max_str_digits global variable:
+#   Python 3.6 doesn't have PyConfig API (PEP 597) nor _PyRuntime.
+# * sys.flags.int_max_str_digits cannot be -1 on Python 3.6: it is
+#   set to the default limit. Adapt test_int_max_str_digits() for that.
+# * Declare _PY_LONG_DEFAULT_MAX_STR_DIGITS and
+#   _PY_LONG_MAX_STR_DIGITS_THRESHOLD macros in longobject.h but only
+#   if the Py_BUILD_CORE macro is defined.
+# * Declare _Py_global_config_int_max_str_digits in pydebug.h.
+#
+#
+# gh-95778: Mention sys.set_int_max_str_digits() in error message (#96874)
+#
+# When ValueError is raised if an integer is larger than the limit,
+# mention sys.set_int_max_str_digits() in the error message.
+#
+#
+# gh-96848: Fix -X int_max_str_digits option parsing (#96988)
+#
+# Fix command line parsing: reject "-X int_max_str_digits" option with
+# no value (invalid) when the PYTHONINTMAXSTRDIGITS environment
+# variable is set to a valid limit.
+Patch387: 00387-cve-2020-10735-prevent-dos-by-very-large-int.patch
+
+# 00394 #
+# CVE-2022-45061: CPU denial of service via inefficient IDNA decoder
+#
+# gh-98433: Fix quadratic time idna decoding.
+#
+# There was an unnecessary quadratic loop in idna decoding. This restores
+# the behavior to linear.
+Patch394: 00394-cve-2022-45061-cpu-denial-of-service-via-inefficient-idna-decoder.patch
+
 # (New patches go here ^^^)
 #
 # When adding new patches to "python" and "python3" in Fedora, EL, etc.,
@@ -1037,6 +1107,9 @@ git apply %{PATCH351}
 %patch377 -p1
 %patch378 -p1
 %patch382 -p1
+%patch386 -p1
+%patch387 -p1
+%patch394 -p1
 
 # Remove files that should be generated by the build
 # (This is after patching, so that we can use patches directly from upstream)
@@ -1962,6 +2035,10 @@ fi
 # ======================================================
 
 %changelog
+* Wed Dec 21 2022 Charalampos Stratakis <cstratak@redhat.com> - 3.6.8-48.1
+- Security fixes for CVE-2020-10735, CVE-2021-28861 and CVE-2022-45061
+Resolves: rhbz#1834423, rhbz#2120642, rhbz#2144072
+
 * Thu Oct 20 2022 Charalampos Stratakis <cstratak@redhat.com> - 3.6.8-48
 - Release bump
 Resolves: rhbz#2136436