From f0d70b3e03ea6e2d690146a801216273df9f46b7 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Thu, 22 Oct 2026 05:22:06 +0000 Subject: [PATCH] gh-161090: Reject a leading delimiter in the punycode decoder RFC 3492 section 6.2 only consumes the delimiter when at least one basic code point precedes it. A leading "-" is now an invalid digit. --- Lib/encodings/punycode.py | 5 ++++- Lib/test/test_codecs.py | 4 ++++ .../Library/2026-10-22-05-19-56.gh-issue-161090.pxZ1IA.rst | 3 +++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-10-22-05-19-56.gh-issue-161090.pxZ1IA.rst diff --git a/Lib/encodings/punycode.py b/Lib/encodings/punycode.py index 279245f435e1791..1da012229837f05 100644 --- a/Lib/encodings/punycode.py +++ b/Lib/encodings/punycode.py @@ -190,7 +190,10 @@ def punycode_decode(text, errors): text = text.encode("ascii") if isinstance(text, memoryview): text = bytes(text) - pos = text.rfind(b"-") + # RFC 3492, section 6.2: the delimiter is only consumed if at least one + # basic code point precedes it. A leading "-" is left in the extended + # part, where it is an invalid digit. + pos = text.rfind(b"-", 1) if pos == -1: base = "" extended = text.upper() diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index 37ac57063c35390..4dbc7a480fc8f41 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -1390,7 +1390,11 @@ def test_decode_invalid(self): (b"Proprostnemluvesky-&uyb24dma41a", "strict", UnicodeDecodeError("punycode", b"", 19, 20, "")), (b"Proprostnemluvesky-uyb24d&ma41a", "strict", UnicodeDecodeError("punycode", b"", 25, 26, "")), (b"Proprostnemluvesky-uyb24dma41a&", "strict", UnicodeDecodeError("punycode", b"", 30, 31, "")), + # A delimiter not preceded by any basic code point (RFC 3492, 6.2) + (b"-", "strict", UnicodeDecodeError("punycode", b"", 0, 1, "")), + (b"-80a1acny", "strict", UnicodeDecodeError("punycode", b"", 0, 1, "")), (b"xn--w&", "ignore", "xn-"), + (b"-80a1acny", "ignore", ""), ] for puny, errors, expected in testcases: with self.subTest(puny=puny, errors=errors): diff --git a/Misc/NEWS.d/next/Library/2026-10-22-05-19-56.gh-issue-161090.pxZ1IA.rst b/Misc/NEWS.d/next/Library/2026-10-22-05-19-56.gh-issue-161090.pxZ1IA.rst new file mode 100644 index 000000000000000..40b506b39cc4332 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-22-05-19-56.gh-issue-161090.pxZ1IA.rst @@ -0,0 +1,3 @@ +Fix the ``punycode`` codec accepting a delimiter (``-``) that is not preceded +by any basic code point. Such input, for example ``b'-80a1acny'``, now raises +:exc:`UnicodeDecodeError`, as required by :rfc:`3492`.