From 198af77c959dad6f51c0b52fb96638a97cef6fe1 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 57c9bc255b2a9a..91947575f8a472 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -1167,6 +1167,13 @@ New deprecations (Contributed by Bénédikt Tran in :gh:`134978`.) +* :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 2bc61662459992..68cfc26d7e7a44 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -116,11 +116,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 7eec34f2f294ad..c1e173fbbc68a2 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -625,8 +625,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) @@ -647,6 +649,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 @@ -724,6 +730,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: @@ -740,6 +748,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 @@ -943,9 +955,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) @@ -960,6 +982,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 07a22672bd51470d5ef7cefc907442a9a143e867 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 222df7621f5fba40268c72fe9ec673e7a9855b96 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 8ff0b14759a6a6985d47cfc09f724320702367df 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 69768c37412c66c1ab081b96ddc23ad12c6c13b8 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 c1e173fbbc68a2..f9e397d0087a84 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -650,9 +650,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 @@ -663,6 +661,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") @@ -749,9 +749,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 @@ -761,6 +759,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):