https://github.com/python/cpython/commit/fab449bddbc4ff03677d49448cf6ea1f9d6a319f
commit: fab449bddbc4ff03677d49448cf6ea1f9d6a319f
branch: main
author: Thomas Kowalski <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-06-06T13:04:23+03:00
summary:
gh-149835: Use realpath() instead of abspath() in shutil.move() (GH-149986)
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 c8d02bbaeb80b4e..4d5a283662101c4 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -944,8 +944,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 59cb319b0a95b5e..bb901220fb408c1 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -2914,6 +2914,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]