--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected], [email protected]
Control: affects -1 + src:python-idna
User: [email protected]
Usertags: pu
* CVE-2026-45409: DoS from specially crafted inputs (Closes: #1139164)
diffstat for python-idna-3.10 python-idna-3.10
changelog | 7
+
patches/0001-Merge-commit-from-fork.patch | 69
+++++++++
patches/0002-Use-valid_string_length-for-early-oversized-input-ch.patch | 46
++++++
patches/0003-Enforce-early-length-limits-in-check_label.patch | 70
++++++++++
patches/series | 3
5 files changed, 195 insertions(+)
diff -Nru python-idna-3.10/debian/changelog python-idna-3.10/debian/changelog
--- python-idna-3.10/debian/changelog 2025-02-06 15:51:11.000000000 +0200
+++ python-idna-3.10/debian/changelog 2026-06-27 20:30:37.000000000 +0300
@@ -1,3 +1,10 @@
+python-idna (3.10-1+deb13u1) trixie; urgency=medium
+
+ * Non-maintainer upload.
+ * CVE-2026-45409: DoS from specially crafted inputs (Closes: #1139164)
+
+ -- Adrian Bunk <[email protected]> Sat, 27 Jun 2026 20:30:37 +0300
+
python-idna (3.10-1) unstable; urgency=medium
* Team upload.
diff -Nru python-idna-3.10/debian/patches/0001-Merge-commit-from-fork.patch
python-idna-3.10/debian/patches/0001-Merge-commit-from-fork.patch
--- python-idna-3.10/debian/patches/0001-Merge-commit-from-fork.patch
1970-01-01 02:00:00.000000000 +0200
+++ python-idna-3.10/debian/patches/0001-Merge-commit-from-fork.patch
2026-06-27 20:23:45.000000000 +0300
@@ -0,0 +1,69 @@
+From 839cbaa1228d7ce819fc9970d9fe6e338538b854 Mon Sep 17 00:00:00 2001
+From: Kim Davies <[email protected]>
+Date: Sun, 10 May 2026 08:47:22 -0700
+Subject: 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 9115f12..e5fa5c3 100644
+--- a/idna/core.py
++++ b/idna/core.py
+@@ -377,6 +377,15 @@ def encode(
+ raise IDNAError("should pass a unicode string to the function
rather than a byte string.")
+ 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:
+@@ -415,6 +424,11 @@ def decode(
+ raise IDNAError("Invalid ASCII in A-label")
+ 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 b59f5e5..ff24ebf 100755
+--- a/tests/test_idna.py
++++ b/tests/test_idna.py
+@@ -80,6 +80,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):
+ la = "\u0061"
+ r = "\u05d0"
+--
+2.47.3
+
diff -Nru
python-idna-3.10/debian/patches/0002-Use-valid_string_length-for-early-oversized-input-ch.patch
python-idna-3.10/debian/patches/0002-Use-valid_string_length-for-early-oversized-input-ch.patch
---
python-idna-3.10/debian/patches/0002-Use-valid_string_length-for-early-oversized-input-ch.patch
1970-01-01 02:00:00.000000000 +0200
+++
python-idna-3.10/debian/patches/0002-Use-valid_string_length-for-early-oversized-input-ch.patch
2026-06-27 20:23:45.000000000 +0300
@@ -0,0 +1,46 @@
+From 099f7900b9e65a690d1fb68a09f416e460ea5e94 Mon Sep 17 00:00:00 2001
+From: Kim Davies <[email protected]>
+Date: Sun, 10 May 2026 12:44:47 -0700
+Subject: Use valid_string_length() for early oversized-input check
+
+---
+ idna/core.py | 16 ++++++----------
+ 1 file changed, 6 insertions(+), 10 deletions(-)
+
+diff --git a/idna/core.py b/idna/core.py
+index e5fa5c3..a8760ef 100644
+--- a/idna/core.py
++++ b/idna/core.py
+@@ -378,12 +378,9 @@ def encode(
+ 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:
++ # Reject inputs that exceed the maximum DNS domain length up-front
++ # to avoid expensive computation on long inputs.
++ if not valid_string_length(s, trailing_dot=True):
+ raise IDNAError("Domain too long")
+
+ trailing_dot = False
+@@ -424,10 +421,9 @@ def decode(
+ raise IDNAError("Invalid ASCII in A-label")
+ 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:
++ # Reject inputs that exceed the maximum DNS domain length up-front
++ # to avoid expensive computation on long inputs.
++ if not valid_string_length(s, trailing_dot=True):
+ raise IDNAError("Domain too long")
+ trailing_dot = False
+ result = []
+--
+2.47.3
+
diff -Nru
python-idna-3.10/debian/patches/0003-Enforce-early-length-limits-in-check_label.patch
python-idna-3.10/debian/patches/0003-Enforce-early-length-limits-in-check_label.patch
---
python-idna-3.10/debian/patches/0003-Enforce-early-length-limits-in-check_label.patch
1970-01-01 02:00:00.000000000 +0200
+++
python-idna-3.10/debian/patches/0003-Enforce-early-length-limits-in-check_label.patch
2026-06-27 20:23:45.000000000 +0300
@@ -0,0 +1,70 @@
+From 8388441c012bfc26227f523df68ca289ad2d75f0 Mon Sep 17 00:00:00 2001
+From: metsw24-max <[email protected]>
+Date: Mon, 11 May 2026 20:59:30 +0530
+Subject: 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 a8760ef..c4b80db 100644
+--- a/idna/core.py
++++ b/idna/core.py
+@@ -247,6 +247,17 @@ def check_label(label: Union[str, bytes, bytearray]) ->
None:
+ 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 ff24ebf..9832c39 100755
+--- a/tests/test_idna.py
++++ b/tests/test_idna.py
+@@ -93,6 +93,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):
+ la = "\u0061"
+ r = "\u05d0"
+--
+2.47.3
+
diff -Nru python-idna-3.10/debian/patches/series
python-idna-3.10/debian/patches/series
--- python-idna-3.10/debian/patches/series 2025-02-03 01:48:08.000000000
+0200
+++ python-idna-3.10/debian/patches/series 2026-06-27 20:26:54.000000000
+0300
@@ -1 +1,4 @@
fix-import.patch
+0001-Merge-commit-from-fork.patch
+0002-Use-valid_string_length-for-early-oversized-input-ch.patch
+0003-Enforce-early-length-limits-in-check_label.patch
--- End Message ---