https://github.com/python/cpython/commit/73f91885871388a97b679766d128286336b839a9 commit: 73f91885871388a97b679766d128286336b839a9 branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: serhiy-storchaka <[email protected]> date: 2026-06-06T13:29:32+03:00 summary:
[3.13] gh-149835: Use realpath() instead of abspath() in shutil.move() (GH-149986) (GH-151011) (cherry picked from commit fab449bddbc4ff03677d49448cf6ea1f9d6a319f) Co-authored-by: Thomas Kowalski <[email protected]> files: A Misc/NEWS.d/next/Security/2026-05-18-17-46-00.gh-issue-149835.EebFlk.rst M Lib/shutil.py M Lib/test/test_shutil.py diff --git a/Lib/shutil.py b/Lib/shutil.py index 44f12d8a22f96ba..e3dd8b1b0849dcb 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -878,8 +878,8 @@ def move(src, dst, copy_function=copy2): return real_dst def _destinsrc(src, dst): - src = os.path.abspath(src) - dst = os.path.abspath(dst) + src = os.path.realpath(src) + dst = os.path.realpath(dst) if not src.endswith(os.path.sep): src += os.path.sep if not dst.endswith(os.path.sep): diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index be900312afe3c24..1469b7cc9576668 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -2891,6 +2891,23 @@ def test_destinsrc_false_positive(self): finally: os_helper.rmtree(TESTFN) + @os_helper.skip_unless_symlink + def test_destinsrc_symlink_bypass(self): + tmp = self.mkdtemp() + src = os.path.join(tmp, 'src') + os.makedirs(src) + # tmp/link -> tmp (one level up) + link = os.path.join(tmp, 'link') + os.symlink(tmp, link) + # raw path: tmp/link/src/sub - no src prefix in string space + # real path: tmp/src/sub - physically inside src + dst = os.path.join(link, 'src', 'sub') + self.assertTrue( + shutil._destinsrc(src, dst), + msg='_destinsrc failed to detect dst inside src via symlink ' + '(dst=%s, src=%s)' % (dst, src), + ) + @os_helper.skip_unless_symlink @mock_rename def test_move_file_symlink(self): diff --git a/Misc/NEWS.d/next/Security/2026-05-18-17-46-00.gh-issue-149835.EebFlk.rst b/Misc/NEWS.d/next/Security/2026-05-18-17-46-00.gh-issue-149835.EebFlk.rst new file mode 100644 index 000000000000000..20cab736552486d --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-05-18-17-46-00.gh-issue-149835.EebFlk.rst @@ -0,0 +1,3 @@ +:func:`shutil.move` now resolves symlinks via :func:`os.path.realpath` +when checking whether the destination is inside the source directory, +preventing a symlink-based bypass of that guard. _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
