From 92051184980b427fc1bb12b70206575c67ef53d4 Mon Sep 17 00:00:00 2001 From: Mark Byrne Date: Tue, 13 Jan 2026 15:49:38 +0100 Subject: [PATCH 1/5] gh-79459: Sanitize the ``prefix`` and ``suffix`` parameters to the `tempfile` functions: - `tempfile.mkdtemp`. - `tempfile.mkstemp`. - `tempfile.NamedTemporaryFile`. --- Doc/whatsnew/3.15.rst | 7 +++++++ Lib/tempfile.py | 4 ++++ Lib/test/test_tempfile.py | 30 ++++++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 69283f67487b18..9d8ebb9e39c905 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -1593,6 +1593,13 @@ New deprecations (Contributed by Sergey B Kirpichev and Serhiy Storchaka in :gh:`143715`.) +* :mod:`tempfile`: + + * The ``prefix`` and ``suffix`` parameters of the tempfile functions, + :func:`tempfile.mkdtemp`, :func:`tempfile.mkstemp` and + :func:`tempfile.NamedTemporaryFile`, will be sanitized to use only the + basename of the provided values if they contain a directory separator. + * ``__version__`` * The ``__version__``, ``version`` and ``VERSION`` attributes have been diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 6dac9ab3c41717..3b3717843f2338 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -117,11 +117,15 @@ def _sanitize_params(prefix, suffix, dir): output_type = _infer_return_type(prefix, suffix, dir) if suffix is None: suffix = output_type() + elif _os.path.dirname(suffix): + suffix = _os.path.basename(suffix) if prefix is None: if output_type is str: prefix = template else: prefix = _os.fsencode(template) + elif _os.path.dirname(prefix): + prefix = _os.path.basename(prefix) if dir is None: if output_type is str: dir = gettempdir() diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index b2b5390af33b00..15bd832dae6b64 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -644,8 +644,10 @@ def do_create(self, dir=None, pre=None, suf=None): dir = tempfile.gettempdirb() if pre is None: pre = output_type() + pre = os.path.basename(pre) if suf is None: suf = output_type() + suf = os.path.basename(suf) (fd, name) = tempfile.mkstemp(dir=dir, prefix=pre, suffix=suf) (ndir, nbase) = os.path.split(name) adir = os.path.abspath(dir) @@ -666,6 +668,10 @@ def test_basic(self): self.do_create(pre="a", suf="b") self.do_create(pre="aa", suf=".txt") self.do_create(dir=".") + self.do_create(pre=f"{os.sep}myhome") + self.do_create(pre=os.fsencode(f"{os.sep}home")) + self.do_create(suf=f"{os.sep}home") + self.do_create(suf=os.fsencode(f"{os.sep}home")) def test_basic_with_bytes_names(self): # mkstemp can create files when given name parts all @@ -743,6 +749,8 @@ def do_create(self, dir=None, pre=None, suf=None): pre = output_type() if suf is None: suf = output_type() + pre = os.path.basename(pre) + suf = os.path.basename(suf) name = tempfile.mkdtemp(dir=dir, prefix=pre, suffix=suf) try: @@ -759,6 +767,10 @@ def test_basic(self): os.rmdir(self.do_create(suf="b")) os.rmdir(self.do_create(pre="a", suf="b")) os.rmdir(self.do_create(pre="aa", suf=".txt")) + os.rmdir(self.do_create(pre=f"{os.sep}home")) + os.rmdir(self.do_create(pre=os.fsencode(f"{os.sep}home"))) + os.rmdir(self.do_create(suf=f"{os.sep}home")) + os.rmdir(self.do_create(suf=os.fsencode(f"{os.sep}home"))) def test_basic_with_bytes_names(self): # mkdtemp can create directories when given all binary parts @@ -962,9 +974,19 @@ def test_many(self): class TestNamedTemporaryFile(BaseTestCase): """Test NamedTemporaryFile().""" - def do_create(self, dir=None, pre="", suf="", delete=True): + def do_create(self, dir=None, pre=None, suf=None, delete=True): + output_type = tempfile._infer_return_type(dir, pre, suf) if dir is None: - dir = tempfile.gettempdir() + if output_type is str: + dir = tempfile.gettempdir() + else: + dir = tempfile.gettempdirb() + if pre is None: + pre = output_type() + if suf is None: + suf = output_type() + pre = os.path.basename(pre) + suf = os.path.basename(suf) file = tempfile.NamedTemporaryFile(dir=dir, prefix=pre, suffix=suf, delete=delete) @@ -979,6 +1001,10 @@ def test_basic(self): self.do_create(suf="b") self.do_create(pre="a", suf="b") self.do_create(pre="aa", suf=".txt") + self.do_create(pre=f"{os.sep}home") + self.do_create(pre=os.fsencode(f"{os.sep}home")) + self.do_create(suf=f"{os.sep}home") + self.do_create(suf=os.fsencode(f"{os.sep}home")) def test_method_lookup(self): # Issue #18879: Looking up a temporary file method should keep it From 810536da8e0bafa5a58687fa300ac5108a919408 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 09:52:55 +0000 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2026-01-16-09-52-54.gh-issue-79459:.x1acn-.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-01-16-09-52-54.gh-issue-79459:.x1acn-.rst diff --git a/Misc/NEWS.d/next/Library/2026-01-16-09-52-54.gh-issue-79459:.x1acn-.rst b/Misc/NEWS.d/next/Library/2026-01-16-09-52-54.gh-issue-79459:.x1acn-.rst new file mode 100644 index 00000000000000..06ae5cf4f16213 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-16-09-52-54.gh-issue-79459:.x1acn-.rst @@ -0,0 +1,2 @@ +Sanitize the ``prefix`` and ``suffix`` arguments to the functions: :func:`tempfile.mkdtemp`, :func:`tempfile.mkstemp` and :func:`tempfile.NamedTemporaryFile`. +If the value of ``prefix`` or ``suffix`` contain a directory separator then the basename of the value is used. From 552b19f391d4ae5a2e280fd0ae1ced6f4361c9e5 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 09:57:19 +0000 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2026-01-16-09-57-17.gh-issue-79459.x1acn-.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-01-16-09-57-17.gh-issue-79459.x1acn-.rst diff --git a/Misc/NEWS.d/next/Library/2026-01-16-09-57-17.gh-issue-79459.x1acn-.rst b/Misc/NEWS.d/next/Library/2026-01-16-09-57-17.gh-issue-79459.x1acn-.rst new file mode 100644 index 00000000000000..06ae5cf4f16213 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-16-09-57-17.gh-issue-79459.x1acn-.rst @@ -0,0 +1,2 @@ +Sanitize the ``prefix`` and ``suffix`` arguments to the functions: :func:`tempfile.mkdtemp`, :func:`tempfile.mkstemp` and :func:`tempfile.NamedTemporaryFile`. +If the value of ``prefix`` or ``suffix`` contain a directory separator then the basename of the value is used. From 679417471f58fe3bbd5cea51c685466434f5475f Mon Sep 17 00:00:00 2001 From: Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com> Date: Fri, 16 Jan 2026 10:58:13 +0100 Subject: [PATCH 4/5] Delete Misc/NEWS.d/next/Library/2026-01-16-09-52-54.gh-issue-79459:.x1acn-.rst Remove news file that was incorrectly named. --- .../next/Library/2026-01-16-09-52-54.gh-issue-79459:.x1acn-.rst | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 Misc/NEWS.d/next/Library/2026-01-16-09-52-54.gh-issue-79459:.x1acn-.rst diff --git a/Misc/NEWS.d/next/Library/2026-01-16-09-52-54.gh-issue-79459:.x1acn-.rst b/Misc/NEWS.d/next/Library/2026-01-16-09-52-54.gh-issue-79459:.x1acn-.rst deleted file mode 100644 index 06ae5cf4f16213..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-01-16-09-52-54.gh-issue-79459:.x1acn-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Sanitize the ``prefix`` and ``suffix`` arguments to the functions: :func:`tempfile.mkdtemp`, :func:`tempfile.mkstemp` and :func:`tempfile.NamedTemporaryFile`. -If the value of ``prefix`` or ``suffix`` contain a directory separator then the basename of the value is used. From ddbef77110d2d9195172121a02f1fe0a718a5b5c Mon Sep 17 00:00:00 2001 From: Mark Byrne Date: Fri, 16 Jan 2026 11:13:16 +0100 Subject: [PATCH 5/5] Move the new tests to the existing test function which tests files named with bytes. --- Lib/test/test_tempfile.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index 15bd832dae6b64..f322cae934222f 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -669,9 +669,7 @@ def test_basic(self): self.do_create(pre="aa", suf=".txt") self.do_create(dir=".") self.do_create(pre=f"{os.sep}myhome") - self.do_create(pre=os.fsencode(f"{os.sep}home")) self.do_create(suf=f"{os.sep}home") - self.do_create(suf=os.fsencode(f"{os.sep}home")) def test_basic_with_bytes_names(self): # mkstemp can create files when given name parts all @@ -682,6 +680,8 @@ def test_basic_with_bytes_names(self): self.do_create(dir=d, suf=b"b") self.do_create(dir=d, pre=b"a", suf=b"b") self.do_create(dir=d, pre=b"aa", suf=b".txt") + self.do_create(dir=d, pre=os.fsencode(f"{os.sep}home")) + self.do_create(dir=d, suf=os.fsencode(f"{os.sep}home")) self.do_create(dir=b".") with self.assertRaises(TypeError): self.do_create(dir=".", pre=b"aa", suf=b".txt") @@ -768,9 +768,7 @@ def test_basic(self): os.rmdir(self.do_create(pre="a", suf="b")) os.rmdir(self.do_create(pre="aa", suf=".txt")) os.rmdir(self.do_create(pre=f"{os.sep}home")) - os.rmdir(self.do_create(pre=os.fsencode(f"{os.sep}home"))) os.rmdir(self.do_create(suf=f"{os.sep}home")) - os.rmdir(self.do_create(suf=os.fsencode(f"{os.sep}home"))) def test_basic_with_bytes_names(self): # mkdtemp can create directories when given all binary parts @@ -780,6 +778,8 @@ def test_basic_with_bytes_names(self): os.rmdir(self.do_create(dir=d, suf=b"b")) os.rmdir(self.do_create(dir=d, pre=b"a", suf=b"b")) os.rmdir(self.do_create(dir=d, pre=b"aa", suf=b".txt")) + os.rmdir(self.do_create(dir=d, pre=os.fsencode(f"{os.sep}home"))) + os.rmdir(self.do_create(dir=d, suf=os.fsencode(f"{os.sep}home"))) with self.assertRaises(TypeError): os.rmdir(self.do_create(dir=d, pre="aa", suf=b".txt")) with self.assertRaises(TypeError):