Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python312 for openSUSE:Factory checked in at 2026-06-22 18:05:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python312 (Old) and /work/SRC/openSUSE:Factory/.python312.new.1956 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python312" Mon Jun 22 18:05:04 2026 rev:49 rq:1360565 version:3.12.13 Changes: -------- --- /work/SRC/openSUSE:Factory/python312/python312.changes 2026-04-09 16:21:39.078884328 +0200 +++ /work/SRC/openSUSE:Factory/.python312.new.1956/python312.changes 2026-06-22 18:05:14.012809865 +0200 @@ -1,0 +2,51 @@ +Wed May 13 14:50:25 UTC 2026 - Matej Cepl <[email protected]> + +- Use the system-wide crypto-policies [bsc#1211301] + * Use the system default cipher list instead of hardcoded values + * Add the --with-ssl-default-suites=openssl configure option + +------------------------------------------------------------------- +Mon Apr 27 13:48:41 UTC 2026 - Matej Cepl <[email protected]> + +- CVE-2026-6019: protect against HTML injection by + Base64-encoding cookie values embedded in JS (bsc#1262654, + gh#python/cpython#90309) + CVE-2026-6019-Morsel-js_output.patch + +------------------------------------------------------------------- +Sat Apr 25 16:42:59 UTC 2026 - Matej Cepl <[email protected]> + +- CVE-2026-1502: rejects CR/LF in HTTP tunnel request headers + (bsc#1261969, CVE-2026-1502, gh#python/cpython#146211). + CVE-2026-1502-reject-CRLF-HTTP-tunnel.patch + +------------------------------------------------------------------- +Sat Apr 25 00:14:50 UTC 2026 - Matej Cepl <[email protected]> + +- CVE-2026-4786: fix webbrowser %action substitution bypass of + dash-prefix check (bsc#1262319, gh#python/cpython#148169) + CVE-2026-4786-webbrowser-open-action.patch + +------------------------------------------------------------------- +Fri Apr 24 17:15:39 UTC 2026 - Matej Cepl <[email protected]> + +- CVE-2026-6100: prevent dangling pointer, which can end in the + use-after-free error (bsc#1262098, gh#python/cpython#148395) + CVE-2026-6100-use-after-free-decompression.patch + +------------------------------------------------------------------- +Sat Apr 18 22:53:10 UTC 2026 - Matej Cepl <[email protected]> + +- Rewrite structure of Python interpreter packages. + `python3*` symbols should be now provided by real python3 + packages and its subpackages instead of the virtual provides + (bsc#1258364). + +------------------------------------------------------------------- +Wed Apr 15 18:00:50 UTC 2026 - Matej Cepl <[email protected]> + +- Add CVE-2026-3446-base64-padding.patch preventing ignoring + excess Base64 data after the first padded quad (bsc#1261970, + CVE-2026-3446, gh#python/cpython#145264). + +------------------------------------------------------------------- Old: ---- macros.python3 New: ---- CVE-2026-1502-reject-CRLF-HTTP-tunnel.patch CVE-2026-3446-base64-padding.patch CVE-2026-4786-webbrowser-open-action.patch CVE-2026-6019-Morsel-js_output.patch CVE-2026-6100-use-after-free-decompression.patch ----------(New B)---------- New: (bsc#1261969, CVE-2026-1502, gh#python/cpython#146211). CVE-2026-1502-reject-CRLF-HTTP-tunnel.patch New: - Add CVE-2026-3446-base64-padding.patch preventing ignoring excess Base64 data after the first padded quad (bsc#1261970, New: dash-prefix check (bsc#1262319, gh#python/cpython#148169) CVE-2026-4786-webbrowser-open-action.patch New: gh#python/cpython#90309) CVE-2026-6019-Morsel-js_output.patch New: use-after-free error (bsc#1262098, gh#python/cpython#148395) CVE-2026-6100-use-after-free-decompression.patch ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python312.spec ++++++ --- /var/tmp/diff_new_pack.cDpRpL/_old 2026-06-22 18:05:16.120883417 +0200 +++ /var/tmp/diff_new_pack.cDpRpL/_new 2026-06-22 18:05:16.124883557 +0200 @@ -129,7 +129,6 @@ Source3: baselibs.conf Source4: README.SUSE Source5: externally_managed.in -Source7: macros.python3 Source8: import_failed.py Source9: import_failed.map Source10: pre_checkin.sh @@ -219,9 +218,25 @@ # PATCH-FIX-UPSTREAM CVE-2026-3479-pkgutil_get_data.patch bsc#1259989 [email protected] # pkgutil.get_data() reject invalid resource arguments Patch64: CVE-2026-3479-pkgutil_get_data.patch +# PATCH-FIX-UPSTREAM CVE-2026-3446-base64-padding.patch bsc#1261970 [email protected] +# Do not ignore excess Base64 data after the first padded quad +Patch65: CVE-2026-3446-base64-padding.patch +# PATCH-FIX-UPSTREAM CVE-2026-6100-use-after-free-decompression.patch bsc#1262098 [email protected] +# NULL dangling pointer to avoid use-after-free error +Patch66: CVE-2026-6100-use-after-free-decompression.patch +# PATCH-FIX-UPSTREAM CVE-2026-4786-webbrowser-open-action.patch bsc#1262319 [email protected] +# Fix webbrowser %action substitution bypass of dash-prefix check +Patch67: CVE-2026-4786-webbrowser-open-action.patch +# PATCH-FIX-UPSTREAM CVE-2026-1502-reject-CRLF-HTTP-tunnel.patch bsc#1261969 [email protected] +# Reject CR/LF in HTTP tunnel request headers +Patch68: CVE-2026-1502-reject-CRLF-HTTP-tunnel.patch +# PATCH-FIX-UPSTREAM CVE-2026-6019-Morsel-js_output.patch bsc#1262654 [email protected] +# Base64-encode cookie values embedded in JS +Patch69: CVE-2026-6019-Morsel-js_output.patch ### END OF PATCHES BuildRequires: autoconf-archive BuildRequires: automake +BuildRequires: crypto-policies-scripts BuildRequires: fdupes BuildRequires: gmp-devel BuildRequires: lzma-devel @@ -235,8 +250,9 @@ BuildRequires: pkgconfig(uuid) BuildRequires: pkgconfig(zlib) #!BuildIgnore: gdk-pixbuf-loader-rsvg -%if 0%{?suse_version} >= 1550 -# The provider for python(abi) is in rpm-build-python +%if 0%{?suse_version} >= 1550 && %{without base} +# Skip for the base flavor: rpm-build-python requires python3-base, which +# creates an unresolvable dependency loop when building python3xx-base itself. BuildRequires: rpm-build-python %endif %if 0%{?suse_version} >= 1500 && 0%{?suse_version} < 1599 @@ -272,11 +288,6 @@ Recommends: %{python_pkg_name}-dbm Recommends: %{python_pkg_name}-pip %obsolete_python_versioned -%if %{primary_interpreter} -Provides: python3 = %{python_version} -Provides: python3-readline -Provides: python3-sqlite3 -%endif %endif %{?suse_build_hwcaps_libs} @@ -298,9 +309,6 @@ Summary: TkInter, a Python Tk Interface Requires: %{python_pkg_name} = %{version} %obsolete_python_versioned tk -%if %{primary_interpreter} -Provides: python3-tk = %{version} -%endif %description -n %{python_pkg_name}-tk Python interface to Tk. Tk is the GUI toolkit that comes with Tcl. @@ -309,9 +317,6 @@ Summary: Python Interface to the (N)Curses Library Requires: %{python_pkg_name} = %{version} %obsolete_python_versioned curses -%if %{primary_interpreter} -Provides: python3-curses -%endif %description -n %{python_pkg_name}-curses An easy to use interface to the (n)curses CUI library. CUI stands for @@ -321,9 +326,6 @@ Summary: Python Interface to the GDBM Library Requires: %{python_pkg_name} = %{version} %obsolete_python_versioned dbm -%if %{primary_interpreter} -Provides: python3-dbm -%endif %description -n %{python_pkg_name}-dbm An easy to use interface for Unix DBM databases, and more specifically, @@ -334,9 +336,6 @@ Requires: %{python_pkg_name} = %{version} Requires: %{python_pkg_name}-tk %obsolete_python_versioned idle -%if %{primary_interpreter} -Provides: python3-idle = %{version} -%endif %description -n %{python_pkg_name}-idle IDLE is a Tkinter based integrated development environment for Python. @@ -348,9 +347,6 @@ Summary: Package Documentation for Python 3 Enhances: %{python_pkg_name} = %{python_version} %obsolete_python_versioned doc -%if %{primary_interpreter} -Provides: python3-doc = %{version} -%endif %description -n %{python_pkg_name}-doc Tutorial, Global Module Index, Language Reference, Library Reference, @@ -360,9 +356,6 @@ %package -n %{python_pkg_name}-doc-devhelp Summary: Additional Package Documentation for Python 3 in devhelp format %obsolete_python_versioned doc-devhelp -%if %{primary_interpreter} -Provides: python3-doc-devhelp = %{version} -%endif %description -n %{python_pkg_name}-doc-devhelp Tutorial, Global Module Index, Language Reference, Library Reference, @@ -387,16 +380,10 @@ %obsolete_python_versioned typing # python3-xml was merged into python3, now moved into -base Provides: %{python_pkg_name}-xml = %{version} -%if %{primary_interpreter} -Provides: python3-asyncio = %{version} -Obsoletes: python3-asyncio < %{version} -Provides: python3-base = %{version} -Obsoletes: python3-base < %{version} -Provides: python3-typing = %{version} -Obsoletes: python3-typing < %{version} -Provides: python3-xml = %{version} -Obsoletes: python3-xml < %{version} -%endif +# Explicitly provided because rpm-build-python (which auto-generates this) +# cannot be installed in the base flavor build root due to a bootstrap cycle: +# rpm-build-python -> python3-base -> (this package) +Provides: python(abi) = %{python_version} %description -n %{python_pkg_name}-base Python is an interpreted, object-oriented programming language, and is @@ -415,13 +402,6 @@ Provides: %{python_pkg_name}-2to3 = %{version} Provides: %{python_pkg_name}-demo = %{version} %obsolete_python_versioned tools -%if %{primary_interpreter} -Provides: python3-2to3 = %{version} -Provides: python3-demo = %{version} -Provides: python3-tools = %{version} -Obsoletes: python3-2to3 < %{version} -Obsoletes: python3-demo < %{version} -%endif %description -n %{python_pkg_name}-tools A number of scripts that are useful for building, testing or extending Python, @@ -431,9 +411,6 @@ Summary: Include Files and Libraries Mandatory for Building Python Modules Requires: %{python_pkg_name}-base = %{version} %obsolete_python_versioned devel -%if %{primary_interpreter} -Provides: python3-devel = %{version} -%endif %description -n %{python_pkg_name}-devel The Python programming language's interpreter can be extended with @@ -451,9 +428,6 @@ Requires: %{python_pkg_name} = %{version} Requires: %{python_pkg_name}-tk = %{version} %obsolete_python_versioned testsuite -%if %{primary_interpreter} -Provides: python3-testsuite = %{version} -%endif %description -n %{python_pkg_name}-testsuite Unit tests that are useful for verifying integrity and functionality @@ -741,20 +715,12 @@ done rm -fv %{buildroot}%{dynlib nis} -# overwrite the copied binary with a link -ln -sf python%{python_version} %{buildroot}%{_bindir}/python3 - -# decide to ship python3 or just python3.X -%if !%{primary_interpreter} -# base rm %{buildroot}%{_bindir}/python3 rm %{buildroot}%{_bindir}/pydoc3 rm %{buildroot}%{_mandir}/man1/python3.1 -# devel rm %{buildroot}%{_bindir}/python3-config rm %{buildroot}%{_libdir}/libpython3.so rm %{buildroot}%{_libdir}/pkgconfig/{python3,python3-embed}.pc -%endif %if %{with externally_managed} # PEP-0668 mark this as a distro maintained python @@ -792,7 +758,13 @@ find "$PDOCS" -name "*.bat" -delete # put gdb helper script into place -install -m 755 -D Tools/gdb/libpython.py %{buildroot}%{_datadir}/gdb/auto-load/%{_libdir}/libpython%{python_abi}.so.%{so_major}.%{so_minor}-gdb.py +%define gdb_help_script libpython%{python_abi}.so.%{so_major}.%{so_minor}-gdb.py +install -m 755 -D Tools/gdb/libpython.py \ + %{buildroot}%{_datadir}/gdb/auto-load/%{_libdir}/%{gdb_help_script} +# don't use %python312_fix_shebang_path to avoid circular dependency via +# python-rpm-macros +sed -i "1s@#\!.*python[^ ]*@#\!%{_bindir}/python%{python_version}@" \ + %{buildroot}%{_datadir}/gdb/auto-load/%{_libdir}/%{gdb_help_script} # install devel files to /config #cp Makefile Makefile.pre.in Makefile.pre $RPM_BUILD_ROOT%{sitedir}/config-%{python_abi}/ @@ -800,12 +772,6 @@ # Remove -IVendor/ from python-config boo#1231795 sed -i 's/-IVendor\///' %{buildroot}%{_bindir}/python%{python_abi}-config -# RPM macros -%if %{primary_interpreter} -mkdir -p %{buildroot}%{_rpmconfigdir}/macros.d/ -install -m 644 %{SOURCE7} %{buildroot}%{_rpmconfigdir}/macros.d/ # macros.python3 -%endif - # import_failed hooks FAILDIR=%{buildroot}/%{sitedir}/_import_failed mkdir $FAILDIR @@ -909,16 +875,10 @@ %files -n %{python_pkg_name}-devel %{_libdir}/libpython%{python_abi}.so -%if %{primary_interpreter} -%{_libdir}/libpython3.so -%endif %{_libdir}/pkgconfig/* %{_includedir}/python%{python_abi} %{sitedir}/config-%{python_abi}-* %{_bindir}/python%{python_abi}-config -%if %{primary_interpreter} -%{_bindir}/python3-config -%endif # Own these directories to not depend on gdb %dir %{_datadir}/gdb %dir %{_datadir}/gdb/auto-load @@ -950,9 +910,6 @@ %doc %{_docdir}/%{name}/README.rst %license LICENSE %doc %{_docdir}/%{name}/README.SUSE -%if %{primary_interpreter} -%{_mandir}/man1/python3.1%{?ext_man} -%endif %{_mandir}/man1/python%{python_version}.1%{?ext_man} %if %{with externally_managed} # PEP-0668 @@ -960,10 +917,6 @@ %endif # license text, not a doc because the code can use it at run-time %{sitedir}/LICENSE.txt -# RPM macros -%if %{primary_interpreter} -%{_rpmconfigdir}/macros.d/macros.python3 -%endif # binary parts %dir %{sitedir}/lib-dynload %{dynlib array} @@ -1068,11 +1021,6 @@ # import-failed hooks %{sitedir}/_import_failed %{sitedir}/site-packages/zzzz-import-failed-hooks.pth -# symlinks -%if %{primary_interpreter} -%{_bindir}/python3 -%{_bindir}/pydoc3 -%endif # executables %attr(755, root, root) %{_bindir}/pydoc%{python_version} # %%attr(755, root, root) %%{_bindir}/python%%{python_abi} ++++++ CVE-2026-1502-reject-CRLF-HTTP-tunnel.patch ++++++ >From 9e0d3211ba43caee9142d3008d9930090f40875f Mon Sep 17 00:00:00 2001 From: Seth Larson <[email protected]> Date: Fri, 10 Apr 2026 10:21:42 -0500 Subject: [PATCH] gh-146211: Reject CR/LF in HTTP tunnel request headers (GH-146212) (cherry picked from commit 05ed7ce7ae9e17c23a04085b2539fe6d6d3cef69) Co-authored-by: Seth Larson <[email protected]> Co-authored-by: Illia Volochii <[email protected]> --- Lib/http/client.py | 11 ++ Lib/test/test_httplib.py | 45 ++++++++++ Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst | 2 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst Index: Python-3.12.13/Lib/http/client.py =================================================================== --- Python-3.12.13.orig/Lib/http/client.py 2026-04-25 19:01:35.799997835 +0200 +++ Python-3.12.13/Lib/http/client.py 2026-04-25 19:01:41.133513907 +0200 @@ -972,13 +972,22 @@ return ip def _tunnel(self): + if _contains_disallowed_url_pchar_re.search(self._tunnel_host): + raise ValueError('Tunnel host can\'t contain control characters %r' + % (self._tunnel_host,)) connect = b"CONNECT %s:%d %s\r\n" % ( self._wrap_ipv6(self._tunnel_host.encode("idna")), self._tunnel_port, self._http_vsn_str.encode("ascii")) headers = [connect] for header, value in self._tunnel_headers.items(): - headers.append(f"{header}: {value}\r\n".encode("latin-1")) + header_bytes = header.encode("latin-1") + value_bytes = value.encode("latin-1") + if not _is_legal_header_name(header_bytes): + raise ValueError('Invalid header name %r' % (header_bytes,)) + if _is_illegal_header_value(value_bytes): + raise ValueError('Invalid header value %r' % (value_bytes,)) + headers.append(b"%s: %s\r\n" % (header_bytes, value_bytes)) headers.append(b"\r\n") # Making a single send() call instead of one per line encourages # the host OS to use a more optimal packet size instead of Index: Python-3.12.13/Lib/test/test_httplib.py =================================================================== --- Python-3.12.13.orig/Lib/test/test_httplib.py 2026-04-25 19:01:37.575064295 +0200 +++ Python-3.12.13/Lib/test/test_httplib.py 2026-04-25 19:01:41.133847977 +0200 @@ -369,6 +369,51 @@ with self.assertRaisesRegex(ValueError, 'Invalid header'): conn.putheader(name, value) + def test_invalid_tunnel_headers(self): + cases = ( + ('Invalid\r\nName', 'ValidValue'), + ('Invalid\rName', 'ValidValue'), + ('Invalid\nName', 'ValidValue'), + ('\r\nInvalidName', 'ValidValue'), + ('\rInvalidName', 'ValidValue'), + ('\nInvalidName', 'ValidValue'), + (' InvalidName', 'ValidValue'), + ('\tInvalidName', 'ValidValue'), + ('Invalid:Name', 'ValidValue'), + (':InvalidName', 'ValidValue'), + ('ValidName', 'Invalid\r\nValue'), + ('ValidName', 'Invalid\rValue'), + ('ValidName', 'Invalid\nValue'), + ('ValidName', 'InvalidValue\r\n'), + ('ValidName', 'InvalidValue\r'), + ('ValidName', 'InvalidValue\n'), + ) + for name, value in cases: + with self.subTest((name, value)): + conn = client.HTTPConnection('example.com') + conn.set_tunnel('tunnel', headers={ + name: value + }) + conn.sock = FakeSocket('') + with self.assertRaisesRegex(ValueError, 'Invalid header'): + conn._tunnel() # Called in .connect() + + def test_invalid_tunnel_host(self): + cases = ( + 'invalid\r.host', + '\ninvalid.host', + 'invalid.host\r\n', + 'invalid.host\x00', + 'invalid host', + ) + for tunnel_host in cases: + with self.subTest(tunnel_host): + conn = client.HTTPConnection('example.com') + conn.set_tunnel(tunnel_host) + conn.sock = FakeSocket('') + with self.assertRaisesRegex(ValueError, 'Tunnel host can\'t contain control characters'): + conn._tunnel() # Called in .connect() + def test_headers_debuglevel(self): body = ( b'HTTP/1.1 200 OK\r\n' Index: Python-3.12.13/Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ Python-3.12.13/Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst 2026-04-25 19:01:41.134133585 +0200 @@ -0,0 +1,2 @@ +Reject CR/LF characters in tunnel request headers for the +HTTPConnection.set_tunnel() method. ++++++ CVE-2026-3446-base64-padding.patch ++++++ >From bd4ab523ba664863d40470cc718c566158adfa31 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <[email protected]> Date: Tue, 24 Mar 2026 01:20:26 +0200 Subject: [PATCH] [3.14] gh-145264: Do not ignore excess Base64 data after the first padded quad (GH-145267) (GH-146326) Base64 decoder (see binascii.a2b_base64(), base64.b64decode(), etc) no longer ignores excess data after the first padded quad in non-strict (default) mode. Instead, in conformance with RFC 4648, it ignores the pad character, "=", if it is present before the end of the encoded data. (cherry picked from commit 4561f6418a691b3e89aef0901f53fe0dfb7f7c0e) (cherry picked from commit e31c55121620189a0d1a07b689762d8ca9c1b7fa) Co-authored-by: Serhiy Storchaka <[email protected]> --- Lib/test/test_binascii.py | 35 ++- Misc/NEWS.d/next/Library/2026-02-26-20-13-16.gh-issue-145264.4pggX_.rst | 4 Modules/binascii.c | 95 ++++------ 3 files changed, 74 insertions(+), 60 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-02-26-20-13-16.gh-issue-145264.4pggX_.rst Index: Python-3.12.13/Lib/test/test_binascii.py =================================================================== --- Python-3.12.13.orig/Lib/test/test_binascii.py 2026-04-15 20:00:26.336287241 +0200 +++ Python-3.12.13/Lib/test/test_binascii.py 2026-04-15 20:00:37.138209710 +0200 @@ -136,17 +136,16 @@ _assertRegexTemplate(r'(?i)Excess padding', data, non_strict_mode_expected_result) # Test excess data exceptions - assertExcessData(b'ab==a', b'i') - assertExcessData(b'ab===', b'i') - assertExcessData(b'ab====', b'i') - assertExcessData(b'ab==:', b'i') - assertExcessData(b'abc=a', b'i\xb7') - assertExcessData(b'abc=:', b'i\xb7') - assertExcessData(b'ab==\n', b'i') - assertExcessData(b'abc==', b'i\xb7') - assertExcessData(b'abc===', b'i\xb7') - assertExcessData(b'abc====', b'i\xb7') - assertExcessData(b'abc=====', b'i\xb7') + assertExcessPadding(b'ab===', b'i') + assertExcessPadding(b'ab====', b'i') + assertNonBase64Data(b'ab==:', b'i') + assertExcessData(b'abc=a', b'i\xb7\x1a') + assertNonBase64Data(b'abc=:', b'i\xb7') + assertNonBase64Data(b'ab==\n', b'i') + assertExcessPadding(b'abc==', b'i\xb7') + assertExcessPadding(b'abc===', b'i\xb7') + assertExcessPadding(b'abc====', b'i\xb7') + assertExcessPadding(b'abc=====', b'i\xb7') # Test non-base64 data exceptions assertNonBase64Data(b'\nab==', b'i') @@ -168,6 +167,20 @@ assertExcessPadding(b'abcd====', b'i\xb7\x1d') assertExcessPadding(b'abcd=====', b'i\xb7\x1d') + def test_base64_excess_data(self): + # Test excess data exceptions + def assertExcessData(data, expected): + assert_regex = r'(?i)Excess data' + data = self.type2test(data) + with self.assertRaisesRegex(binascii.Error, assert_regex): + binascii.a2b_base64(data, strict_mode=True) + self.assertEqual(binascii.a2b_base64(data, strict_mode=False), + expected) + self.assertEqual(binascii.a2b_base64(data), expected) + + assertExcessData(b'ab==c=', b'i\xb7') + assertExcessData(b'ab==cd', b'i\xb7\x1d') + assertExcessData(b'abc=d', b'i\xb7\x1d') def test_base64errors(self): # Test base64 with invalid padding Index: Python-3.12.13/Misc/NEWS.d/next/Library/2026-02-26-20-13-16.gh-issue-145264.4pggX_.rst =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ Python-3.12.13/Misc/NEWS.d/next/Library/2026-02-26-20-13-16.gh-issue-145264.4pggX_.rst 2026-04-15 20:00:37.138381544 +0200 @@ -0,0 +1,4 @@ +Base64 decoder (see :func:`binascii.a2b_base64`, :func:`base64.b64decode`, etc) no +longer ignores excess data after the first padded quad in non-strict +(default) mode. Instead, in conformance with :rfc:`4648`, section 3.3, it now ignores +the pad character, "=", if it is present before the end of the encoded data. Index: Python-3.12.13/Modules/binascii.c =================================================================== --- Python-3.12.13.orig/Modules/binascii.c 2026-03-03 13:39:30.000000000 +0100 +++ Python-3.12.13/Modules/binascii.c 2026-04-15 20:00:37.138762021 +0200 @@ -393,7 +393,6 @@ const unsigned char *ascii_data = data->buf; size_t ascii_len = data->len; binascii_state *state = NULL; - char padding_started = 0; /* Allocate the buffer */ Py_ssize_t bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */ @@ -404,14 +403,6 @@ return NULL; unsigned char *bin_data_start = bin_data; - if (strict_mode && ascii_len > 0 && ascii_data[0] == '=') { - state = get_binascii_state(module); - if (state) { - PyErr_SetString(state->Error, "Leading padding not allowed"); - } - goto error_end; - } - int quad_pos = 0; unsigned char leftchar = 0; int pads = 0; @@ -422,35 +413,34 @@ ** the invalid ones. */ if (this_ch == BASE64_PAD) { - padding_started = 1; - - if (strict_mode && quad_pos == 0) { - state = get_binascii_state(module); - if (state) { - PyErr_SetString(state->Error, "Excess padding not allowed"); - } - goto error_end; + pads++; + if (quad_pos >= 2 && quad_pos + pads <= 4) { + continue; } - if (quad_pos >= 2 && quad_pos + ++pads >= 4) { - /* A pad sequence means we should not parse more input. - ** We've already interpreted the data from the quad at this point. - ** in strict mode, an error should raise if there's excess data after the padding. - */ - if (strict_mode && i + 1 < ascii_len) { - state = get_binascii_state(module); - if (state) { - PyErr_SetString(state->Error, "Excess data after padding"); - } - goto error_end; - } - - goto done; + // See RFC 4648, section-3.3: "specifications MAY ignore the + // pad character, "=", treating it as non-alphabet data, if + // it is present before the end of the encoded data" and + // "the excess pad characters MAY also be ignored." + if (!strict_mode) { + continue; } - continue; + if (quad_pos == 1) { + /* Set an error below. */ + break; + } + state = get_binascii_state(module); + if (state) { + PyErr_SetString(state->Error, + (quad_pos == 0 && i == 0) + ? "Leading padding not allowed" + : "Excess padding not allowed"); + } + goto error_end; } this_ch = table_a2b_base64[this_ch]; if (this_ch >= 64) { + // See RFC 4648, section-3.3. if (strict_mode) { state = get_binascii_state(module); if (state) { @@ -461,11 +451,14 @@ continue; } - // Characters that are not '=', in the middle of the padding, are not allowed - if (strict_mode && padding_started) { + // Characters that are not '=', in the middle of the padding, are + // not allowed (except when they are). See RFC 4648, section-3.3. + if (pads && strict_mode) { state = get_binascii_state(module); if (state) { - PyErr_SetString(state->Error, "Discontinuous padding not allowed"); + PyErr_SetString(state->Error, (quad_pos + pads == 4) + ? "Excess data after padding" + : "Discontinuous padding not allowed"); } goto error_end; } @@ -494,31 +487,35 @@ } } - if (quad_pos != 0) { + if (quad_pos == 1) { + /* There is exactly one extra valid, non-padding, base64 character. + * * This is an invalid length, as there is no possible input that + ** could encoded into such a base64 string. + */ state = get_binascii_state(module); - if (state == NULL) { - /* error already set, from get_binascii_state */ - } else if (quad_pos == 1) { - /* - ** There is exactly one extra valid, non-padding, base64 character. - ** This is an invalid length, as there is no possible input that - ** could encoded into such a base64 string. - */ + if (state) { PyErr_Format(state->Error, "Invalid base64-encoded string: " "number of data characters (%zd) cannot be 1 more " "than a multiple of 4", (bin_data - bin_data_start) / 3 * 4 + 1); - } else { + } + goto error_end; + } + + if (quad_pos != 0 && quad_pos + pads < 4) { + state = get_binascii_state(module); + if (state) { PyErr_SetString(state->Error, "Incorrect padding"); } - error_end: - _PyBytesWriter_Dealloc(&writer); - return NULL; + goto error_end; } -done: return _PyBytesWriter_Finish(&writer, bin_data); + +error_end: + _PyBytesWriter_Dealloc(&writer); + return NULL; } ++++++ CVE-2026-4786-webbrowser-open-action.patch ++++++ >From 1016d827af13ad302502b7b27b8479b08e524638 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych <[email protected]> Date: Mon, 13 Apr 2026 20:02:52 +0100 Subject: [PATCH] [3.12] gh-148169: Fix webbrowser `%action` substitution bypass of dash-prefix check (GH-148170) (cherry picked from commit d22922c8a7958353689dc4763dd72da2dea03fff) Co-authored-by: Stan Ulbrych <[email protected]> --- Lib/test/test_webbrowser.py | 9 +++++++++ Lib/webbrowser.py | 5 +++-- Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst Index: Python-3.12.13/Lib/test/test_webbrowser.py =================================================================== --- Python-3.12.13.orig/Lib/test/test_webbrowser.py 2026-04-25 12:58:18.907715078 +0200 +++ Python-3.12.13/Lib/test/test_webbrowser.py 2026-04-25 12:58:18.961715505 +0200 @@ -99,6 +99,15 @@ options=[], arguments=[URL]) + def test_reject_action_dash_prefixes(self): + browser = self.browser_class(name=CMD_NAME) + with self.assertRaises(ValueError): + browser.open('%action--incognito') + # new=1: action is "--new-window", so "%action" itself expands to + # a dash-prefixed flag even with no dash in the original URL. + with self.assertRaises(ValueError): + browser.open('%action', new=1) + class EdgeCommandTest(CommandTestMixin, unittest.TestCase): Index: Python-3.12.13/Lib/webbrowser.py =================================================================== --- Python-3.12.13.orig/Lib/webbrowser.py 2026-04-25 12:58:18.907998903 +0200 +++ Python-3.12.13/Lib/webbrowser.py 2026-04-25 12:58:18.961859987 +0200 @@ -267,7 +267,6 @@ def open(self, url, new=0, autoraise=True): sys.audit("webbrowser.open", url) - self._check_url(url) if new == 0: action = self.remote_action elif new == 1: @@ -281,7 +280,9 @@ raise Error("Bad 'new' parameter to open(); " + "expected 0, 1, or 2, got %s" % new) - args = [arg.replace("%s", url).replace("%action", action) + self._check_url(url.replace("%action", action)) + + args = [arg.replace("%action", action).replace("%s", url) for arg in self.remote_args] args = [arg for arg in args if arg] success = self._invoke(args, True, autoraise, url) Index: Python-3.12.13/Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ Python-3.12.13/Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst 2026-04-25 12:58:18.961975715 +0200 @@ -0,0 +1,2 @@ +A bypass in :mod:`webbrowser` allowed URLs prefixed with ``%action`` to pass +the dash-prefix safety check. ++++++ CVE-2026-6019-Morsel-js_output.patch ++++++ >From a67e6c856353c04782f38bca6d6c1c3d3287c653 Mon Sep 17 00:00:00 2001 From: Seth Larson <[email protected]> Date: Wed, 22 Apr 2026 14:22:31 -0500 Subject: [PATCH] gh-90309: Base64-encode cookie values embedded in JS (cherry picked from commit 76b3923d688c0efc580658476c5f525ec8735104) Co-authored-by: Seth Larson <[email protected]> --- Lib/http/cookies.py | 8 ++ Lib/test/test_http_cookies.py | 29 ++++++---- Misc/NEWS.d/next/Security/2026-04-21-13-46-30.gh-issue-90309.srvj9q.rst | 3 + 3 files changed, 27 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-04-21-13-46-30.gh-issue-90309.srvj9q.rst Index: Python-3.12.13/Lib/http/cookies.py =================================================================== --- Python-3.12.13.orig/Lib/http/cookies.py 2026-04-27 18:44:37.195359134 +0200 +++ Python-3.12.13/Lib/http/cookies.py 2026-04-27 18:44:37.325467491 +0200 @@ -389,17 +389,21 @@ return '<%s: %s>' % (self.__class__.__name__, self.OutputString()) def js_output(self, attrs=None): + import base64 # Print javascript output_string = self.OutputString(attrs) if _has_control_character(output_string): raise CookieError("Control characters are not allowed in cookies") + # Base64-encode value to avoid template + # injection in cookie values. + output_encoded = base64.b64encode(output_string.encode('utf-8')).decode("ascii") return """ <script type="text/javascript"> <!-- begin hiding - document.cookie = \"%s\"; + document.cookie = atob(\"%s\"); // end hiding --> </script> - """ % (output_string.replace('"', r'\"')) + """ % (output_encoded,) def OutputString(self, attrs=None): # Build up our result Index: Python-3.12.13/Lib/test/test_http_cookies.py =================================================================== --- Python-3.12.13.orig/Lib/test/test_http_cookies.py 2026-04-27 18:44:37.195725604 +0200 +++ Python-3.12.13/Lib/test/test_http_cookies.py 2026-04-27 18:44:37.325735506 +0200 @@ -1,5 +1,5 @@ # Simple test suite for http/cookies.py - +import base64 import copy import unittest import doctest @@ -152,17 +152,19 @@ self.assertEqual(C.output(['path']), 'Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme') - self.assertEqual(C.js_output(), r""" + cookie_encoded = base64.b64encode(b'Customer="WILE_E_COYOTE"; Path=/acme; Version=1').decode('ascii') + self.assertEqual(C.js_output(), fr""" <script type="text/javascript"> <!-- begin hiding - document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1"; + document.cookie = atob("{cookie_encoded}"); // end hiding --> </script> """) - self.assertEqual(C.js_output(['path']), r""" + cookie_encoded = base64.b64encode(b'Customer="WILE_E_COYOTE"; Path=/acme').decode('ascii') + self.assertEqual(C.js_output(['path']), fr""" <script type="text/javascript"> <!-- begin hiding - document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme"; + document.cookie = atob("{cookie_encoded}"); // end hiding --> </script> """) @@ -259,17 +261,19 @@ self.assertEqual(C.output(['path']), 'Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme') - self.assertEqual(C.js_output(), r""" + expected_encoded_cookie = base64.b64encode(b'Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1').decode('ascii') + self.assertEqual(C.js_output(), fr""" <script type="text/javascript"> <!-- begin hiding - document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1"; + document.cookie = atob("{expected_encoded_cookie}"); // end hiding --> </script> """) - self.assertEqual(C.js_output(['path']), r""" + expected_encoded_cookie = base64.b64encode(b'Customer=\"WILE_E_COYOTE\"; Path=/acme').decode('ascii') + self.assertEqual(C.js_output(['path']), fr""" <script type="text/javascript"> <!-- begin hiding - document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme"; + document.cookie = atob("{expected_encoded_cookie}"); // end hiding --> </script> """) @@ -360,13 +364,16 @@ self.assertEqual( M.output(), "Set-Cookie: %s=%s; Path=/foo" % (i, "%s_coded_val" % i)) + expected_encoded_cookie = base64.b64encode( + ("%s=%s; Path=/foo" % (i, "%s_coded_val" % i)).encode("ascii") + ).decode('ascii') expected_js_output = """ <script type="text/javascript"> <!-- begin hiding - document.cookie = "%s=%s; Path=/foo"; + document.cookie = atob("%s"); // end hiding --> </script> - """ % (i, "%s_coded_val" % i) + """ % (expected_encoded_cookie,) self.assertEqual(M.js_output(), expected_js_output) for i in ["foo bar", "foo@bar"]: # Try some illegal characters Index: Python-3.12.13/Misc/NEWS.d/next/Security/2026-04-21-13-46-30.gh-issue-90309.srvj9q.rst =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ Python-3.12.13/Misc/NEWS.d/next/Security/2026-04-21-13-46-30.gh-issue-90309.srvj9q.rst 2026-04-27 18:44:37.325970118 +0200 @@ -0,0 +1,3 @@ +Base64-encode values when embedding cookies to JavaScript using the +:meth:`http.cookies.BaseCookie.js_output` method to avoid injection +and escaping. ++++++ CVE-2026-6100-use-after-free-decompression.patch ++++++ >From e100aea7aded26a49abe96c3aae2d64ef195f397 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych <[email protected]> Date: Mon, 13 Apr 2026 02:14:54 +0100 Subject: [PATCH 1/3] gh-148395: Fix a possible UAF in `{LZMA,BZ2,_Zlib}Decompressor` (GH-148396) Fix dangling input pointer after `MemoryError` in _lzma/_bz2/_ZlibDecompressor.decompress (cherry picked from commit 8fc66aef6d7b3ae58f43f5c66f9366cc8cbbfcd2) Co-authored-by: Stan Ulbrych <[email protected]> --- Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst | 5 +++++ Modules/_bz2module.c | 1 + Modules/_lzmamodule.c | 1 + Modules/zlibmodule.c | 1 + 4 files changed, 8 insertions(+) create mode 100644 Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst Index: Python-3.12.13/Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ Python-3.12.13/Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst 2026-04-24 23:01:53.772670857 +0200 @@ -0,0 +1,5 @@ +Fix a dangling input pointer in :class:`lzma.LZMADecompressor`, +:class:`bz2.BZ2Decompressor`, and internal :class:`!zlib._ZlibDecompressor` +when memory allocation fails with :exc:`MemoryError`, which could let a +subsequent :meth:`!decompress` call read or write through a stale pointer to +the already-released caller buffer. Index: Python-3.12.13/Modules/_bz2module.c =================================================================== --- Python-3.12.13.orig/Modules/_bz2module.c 2026-03-03 13:39:30.000000000 +0100 +++ Python-3.12.13/Modules/_bz2module.c 2026-04-24 23:01:53.771388251 +0200 @@ -587,6 +587,7 @@ return result; error: + bzs->next_in = NULL; Py_XDECREF(result); return NULL; } Index: Python-3.12.13/Modules/_lzmamodule.c =================================================================== --- Python-3.12.13.orig/Modules/_lzmamodule.c 2026-03-03 13:39:30.000000000 +0100 +++ Python-3.12.13/Modules/_lzmamodule.c 2026-04-24 23:01:53.771598998 +0200 @@ -1114,6 +1114,7 @@ return result; error: + lzs->next_in = NULL; Py_XDECREF(result); return NULL; } Index: Python-3.12.13/Modules/zlibmodule.c =================================================================== --- Python-3.12.13.orig/Modules/zlibmodule.c 2026-03-03 13:39:30.000000000 +0100 +++ Python-3.12.13/Modules/zlibmodule.c 2026-04-24 23:01:53.771855952 +0200 @@ -1645,6 +1645,7 @@ return result; error: + self->zst.next_in = NULL; Py_XDECREF(result); return NULL; } ++++++ _scmsync.obsinfo ++++++ --- /var/tmp/diff_new_pack.cDpRpL/_old 2026-06-22 18:05:16.340891094 +0200 +++ /var/tmp/diff_new_pack.cDpRpL/_new 2026-06-22 18:05:16.344891233 +0200 @@ -1,6 +1,6 @@ -mtime: 1775599364 -commit: 3ee6958228363d684b7ec3e5ba178218792f15c4e524732fbe618a0e2d72e74a -url: https://src.opensuse.org/python-interpreters/python312.git -revision: 3ee6958228363d684b7ec3e5ba178218792f15c4e524732fbe618a0e2d72e74a +mtime: 1778684246 +commit: b0a8df4a45a4e47b801dddcbfef058b41ae370d7dd207ff0ac5e9e558c9b746a +url: https://src.opensuse.org/python-interpreters/python312 +revision: b0a8df4a45a4e47b801dddcbfef058b41ae370d7dd207ff0ac5e9e558c9b746a projectscmsync: https://src.opensuse.org/python-interpreters/_ObsPrj ++++++ build.specials.obscpio ++++++ ++++++ build.specials.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.gitignore new/.gitignore --- old/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/.gitignore 2026-05-13 16:57:26.000000000 +0200 @@ -0,0 +1,6 @@ +_build.* +*.obscpio +*.osc +.osc +.pbuild +python312-3.12.*-build
