From 828ad9d793000870cdfa2389c0ddc13269924baf Mon Sep 17 00:00:00 2001 From: AlmaLinux RelEng Bot Date: Thu, 13 Aug 2026 04:33:08 -0400 Subject: [PATCH] import CS git python-idna-2.10-8.el9_8 --- SOURCES/CVE-2026-45409.patch | 174 +++++++++++++++++++++++++++++++++++ SPECS/python-idna.spec | 11 ++- 2 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 SOURCES/CVE-2026-45409.patch diff --git a/SOURCES/CVE-2026-45409.patch b/SOURCES/CVE-2026-45409.patch new file mode 100644 index 0000000..5cadebd --- /dev/null +++ b/SOURCES/CVE-2026-45409.patch @@ -0,0 +1,174 @@ +From 641dad441dbc63145c70e64bf70a4035508d2426 Mon Sep 17 00:00:00 2001 +From: Kim Davies +Date: Sun, 10 May 2026 08:47:22 -0700 +Subject: [PATCH 1/3] Merge commit from fork + +--- + idna/core.py | 14 ++++++++++++++ + tests/test_idna.py | 13 +++++++++++++ + 2 files changed, 27 insertions(+) + +diff --git a/idna/core.py b/idna/core.py +index 5f54c89..2175d87 100644 +--- a/idna/core.py ++++ b/idna/core.py +@@ -347,6 +347,15 @@ def encode(s, strict=False, uts46=False, std3_rules=False, transitional=False): + s = s.decode("ascii") + if uts46: + s = uts46_remap(s, std3_rules, transitional) ++ ++ # Reject inputs that exceed the maximum DNS domain length up-front. ++ # Each codepoint in a U-label contributes at least one octet to its ++ # A-label form, so any input longer than the domain limit cannot ++ # produce a valid A-domain. Short-circuiting here prevents per-label ++ # validation from being driven into quadratic time ++ if len(s) > 254: ++ raise IDNAError("Domain too long") ++ + trailing_dot = False + result = [] + if strict: +@@ -378,6 +387,11 @@ def decode(s, strict=False, uts46=False, std3_rules=False): + s = s.decode("ascii") + if uts46: + s = uts46_remap(s, std3_rules, False) ++ # See encode() for rationale; the same bound applies because every ++ # legal A-domain is at most 254 octets and every codepoint of a ++ # legal U-domain contributes at least one octet to its A-form. ++ if len(s) > 254: ++ raise IDNAError("Domain too long") + trailing_dot = False + result = [] + if not strict: +diff --git a/tests/test_idna.py b/tests/test_idna.py +index 2d8c450..b32ac8d 100755 +--- a/tests/test_idna.py ++++ b/tests/test_idna.py +@@ -78,6 +78,19 @@ class IDNATests(unittest.TestCase): + self.assertFalse(idna.valid_label_length('a' * 64)) + self.assertRaises(idna.IDNAError, idna.encode, 'a' * 64) + ++ def test_oversized_input_rejected_promptly(self): ++ # GHSA-65pc-fj4g-8rjx: encode/decode must reject inputs that ++ # exceed the maximum DNS domain length before per-codepoint ++ # validation runs, so labels dominated by CONTEXTO codepoints ++ # cannot drive validation into quadratic time. ++ import time ++ ++ for payload in ("٠" * 8000, "・" * 8000 + "漢"): ++ start = time.perf_counter() ++ self.assertRaises(idna.IDNAError, idna.encode, payload) ++ self.assertRaises(idna.IDNAError, idna.decode, payload) ++ self.assertLess(time.perf_counter() - start, 1.0) ++ + def test_check_bidi(self): + + l = u'\u0061' + +From 20ecdf5c96d31f2b95a49d5794417ba9e88f2329 Mon Sep 17 00:00:00 2001 +From: metsw24-max +Date: Mon, 11 May 2026 20:59:30 +0530 +Subject: [PATCH 2/3] Enforce early length limits in check_label + +--- + idna/core.py | 11 +++++++++++ + tests/test_idna.py | 24 ++++++++++++++++++++++++ + 2 files changed, 35 insertions(+) + +diff --git a/idna/core.py b/idna/core.py +index 2175d87..c68254a 100644 +--- a/idna/core.py ++++ b/idna/core.py +@@ -241,6 +241,17 @@ def check_label(label): + label = label.decode('utf-8') + if len(label) == 0: + raise IDNAError('Empty Label') ++ # Reject oversized labels before per-codepoint validation runs. ++ # CONTEXTJ/CONTEXTO checks scan the whole label per codepoint, so an ++ # uncapped label drives validation into quadratic time ++ # (GHSA-65pc-fj4g-8rjx / CVE-2024-3651). encode()/decode() cap the ++ # whole-domain length; this cap protects direct callers of ++ # alabel/ulabel/check_label and the idna2008 incremental codec. ++ # Use the whole-domain bound rather than the per-label DNS bound so ++ # that UTS #46 lenient decoding of labels longer than 63 chars is ++ # preserved. ++ if not valid_string_length(label, trailing_dot=True): ++ raise IDNAError('Label too long') + + check_nfc(label) + check_hyphen_ok(label) +diff --git a/tests/test_idna.py b/tests/test_idna.py +index b32ac8d..1179ebb 100755 +--- a/tests/test_idna.py ++++ b/tests/test_idna.py +@@ -91,6 +91,30 @@ class IDNATests(unittest.TestCase): + self.assertRaises(idna.IDNAError, idna.decode, payload) + self.assertLess(time.perf_counter() - start, 1.0) + ++ def test_oversized_label_rejected_promptly(self): ++ # The whole-domain cap in encode()/decode() does not cover direct ++ # callers of alabel/ulabel/check_label, nor the idna2008 ++ # incremental codec which calls alabel/ulabel per label. Without a ++ # per-label cap, a single oversized CONTEXTO-heavy label still ++ # drives validation into quadratic time. ++ import codecs ++ import time ++ ++ import idna.codec # noqa: F401 (register the idna2008 codec) ++ ++ payload = "・" * 8000 + "漢" ++ start = time.perf_counter() ++ self.assertRaises(idna.IDNAError, idna.check_label, payload) ++ self.assertRaises(idna.IDNAError, idna.alabel, payload) ++ self.assertRaises(idna.IDNAError, idna.ulabel, payload) ++ self.assertRaises( ++ idna.IDNAError, ++ codecs.getincrementalencoder("idna2008")().encode, ++ payload, ++ True, ++ ) ++ self.assertLess(time.perf_counter() - start, 1.0) ++ + def test_check_bidi(self): + + l = u'\u0061' + +From 7afc8765eff9626ae584a9f4980e31ecdf148078 Mon Sep 17 00:00:00 2001 +From: RHEL Packaging Agent +Date: Mon, 27 Jul 2026 07:12:26 +0000 +Subject: [PATCH 3/3] Adapt test to use IncrementalEncoder directly for v2.10 + compatibility + +In v2.10, the idna codec is registered as 'idna' not 'idna2008', and +codecs.register() is not called. Use idna.codec.IncrementalEncoder +directly instead of codecs.getincrementalencoder('idna2008') to test +the same functionality without requiring the newer codec registration. +--- + tests/test_idna.py | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/tests/test_idna.py b/tests/test_idna.py +index 1179ebb..854de15 100755 +--- a/tests/test_idna.py ++++ b/tests/test_idna.py +@@ -97,10 +97,9 @@ class IDNATests(unittest.TestCase): + # incremental codec which calls alabel/ulabel per label. Without a + # per-label cap, a single oversized CONTEXTO-heavy label still + # drives validation into quadratic time. +- import codecs + import time + +- import idna.codec # noqa: F401 (register the idna2008 codec) ++ from idna.codec import IncrementalEncoder + + payload = "・" * 8000 + "漢" + start = time.perf_counter() +@@ -109,7 +108,7 @@ class IDNATests(unittest.TestCase): + self.assertRaises(idna.IDNAError, idna.ulabel, payload) + self.assertRaises( + idna.IDNAError, +- codecs.getincrementalencoder("idna2008")().encode, ++ IncrementalEncoder().encode, + payload, + True, + ) diff --git a/SPECS/python-idna.spec b/SPECS/python-idna.spec index c759e3d..8aec8fa 100644 --- a/SPECS/python-idna.spec +++ b/SPECS/python-idna.spec @@ -2,7 +2,7 @@ Name: python-%{srcname} Version: 2.10 -Release: 7%{?dist}.1 +Release: 8%{?dist} Summary: Internationalized Domain Names in Applications (IDNA) License: BSD and Python and Unicode @@ -14,6 +14,11 @@ Source0: https://pypi.io/packages/source/i/%{srcname}/%{srcname}-%{versio # Tracking bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2274779 Patch: CVE-2024-3651.patch +# Security fix for CVE-2026-45409 +# Upstream: https://github.com/kjd/idna/commit/c0dda4501df5d91c3181ce6f962dc5de74e82cc1 +# Upstream: https://github.com/kjd/idna/commit/e1cb465b6376f33306a26f467d197edbcd01c4b9 +Patch: CVE-2026-45409.patch + BuildArch: noarch BuildRequires: python3-devel @@ -65,6 +70,10 @@ rm -rf %{srcname}.egg-info %{python3_sitelib}/%{srcname}-%{version}-py%{python3_version}.egg-info %changelog +* Mon Jul 27 2026 RHEL Packaging Agent - 2.10-8 +- Security fix for CVE-2026-45409 +Resolves: RHEL-215653 + * Tue Apr 23 2024 Lumír Balhar - 2.10-7.1 - Security fix for CVE-2024-3651 Resolves: RHEL-33464