From 8ad59ebbc09964d0cbcb900c8a051cdbf75a2e15 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Thu, 22 Oct 2026 05:22:19 +0000 Subject: [PATCH] gh-161092: Require an octal mode in the uu codec "begin" line Skip lines starting with "begin" that are not followed by an octal mode, as email.message._decode_uu() does, instead of taking them as the header. --- Lib/encodings/uu_codec.py | 13 ++++++++++-- Lib/test/test_codecs.py | 21 +++++++++++++++++++ ...-10-22-05-20-02.gh-issue-161092.OtC5l6.rst | 4 ++++ 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-10-22-05-20-02.gh-issue-161092.OtC5l6.rst diff --git a/Lib/encodings/uu_codec.py b/Lib/encodings/uu_codec.py index 4f8704016e2131..56ea394a7806de 100644 --- a/Lib/encodings/uu_codec.py +++ b/Lib/encodings/uu_codec.py @@ -46,8 +46,17 @@ def uu_decode(input, errors='strict'): s = readline() if not s: raise ValueError('Missing "begin" line in input data') - if s[:5] == b'begin': - break + # Only a "begin " line, optionally followed by a + # filename, starts the encoded data (as in + # email.message._decode_uu()); anything else is leading text. + if s[:6] != b'begin ': + continue + mode = s[6:].split(b' ', 1)[0] + try: + int(mode, 8) + except ValueError: + continue + break # Decode while True: diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index 37ac57063c3539..3e174fb0130c26 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -3251,6 +3251,27 @@ def test_uu_invalid(self): # Missing "begin" line self.assertRaises(ValueError, codecs.decode, b"", "uu-codec") + def test_uu_begin_line(self): + # Only a "begin []" line starts the encoded + # data; other lines starting with "begin" are leading text. + block = codecs.encode(b"data", "uu-codec") + other = codecs.encode(b"other", "uu-codec").partition(b"\n")[2] + for line in (b"begin 666 name", b"begin 0 name with spaces", + b"begin 644 name\r", b"begin 666"): + with self.subTest(line=line): + encoded = line + b"\n" + other + self.assertEqual(codecs.decode(encoded + block, "uu-codec"), + b"other") + for line in (b"beginning of the text", b"begin", b"begin ", + b"begin mode name", b"begin 888 name", + b"beginx 666 name", b"begin-base64 666 name"): + with self.subTest(line=line): + encoded = line + b"\n" + other + self.assertRaises(ValueError, codecs.decode, + encoded, "uu-codec") + self.assertEqual(codecs.decode(encoded + block, "uu-codec"), + b"data") + # The codec system tries to add notes to exceptions in order to ensure # the error mentions the operation being performed and the codec involved. diff --git a/Misc/NEWS.d/next/Library/2026-10-22-05-20-02.gh-issue-161092.OtC5l6.rst b/Misc/NEWS.d/next/Library/2026-10-22-05-20-02.gh-issue-161092.OtC5l6.rst new file mode 100644 index 00000000000000..abdc68c7f7a5db --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-22-05-20-02.gh-issue-161092.OtC5l6.rst @@ -0,0 +1,4 @@ +Fix the ``uu`` codec decoder taking any line that starts with ``begin``, such +as ``beginning of the report``, as the header of the encoded data. Like the +:mod:`email` package, it now requires ``begin`` followed by an octal mode and +skips other lines as leading text.