Skip to content

Commit be13e86

Browse files
[3.11] gh-151558: Fix symlink escape via tarfile hardlink-extraction fallback (GH-151559) (#152001)
* gh-151558: Fix symlink escape via `tarfile` hardlink-extraction fallback (GH-151559) (cherry picked from commit 27dd970) Co-authored-by: Stan Ulbrych <stan@python.org> * Can't use `:cve:` on 3.11 --------- Co-authored-by: Stan Ulbrych <stan@python.org>
1 parent 7f0dc59 commit be13e86

3 files changed

Lines changed: 30 additions & 0 deletions

File tree

Lib/tarfile.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2665,6 +2665,9 @@ def makelink_with_filter(self, tarinfo, targetpath,
26652665
"makelink_with_filter: if filter_function is not None, "
26662666
+ "extraction_root must also not be None")
26672667
try:
2668+
filter_function(
2669+
unfiltered.replace(name=tarinfo.name, deep=False),
2670+
extraction_root)
26682671
filtered = filter_function(unfiltered, extraction_root)
26692672
except _FILTER_ERRORS as cause:
26702673
raise LinkFallbackError(tarinfo, unfiltered.name) from cause

Lib/test/test_tarfile.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3998,6 +3998,30 @@ def test_sneaky_hardlink_fallback(self):
39983998
self.expect_file("boom", symlink_to='../../link_here')
39993999
self.expect_file("c", symlink_to='b')
40004000

4001+
@symlink_test
4002+
def test_sneaky_hardlink_fallback_deep(self):
4003+
# (CVE-2026-11940)
4004+
with ArchiveMaker() as arc:
4005+
arc.add("a/b/s", symlink_to=os.path.join("..", "escape"))
4006+
arc.add("s", hardlink_to=os.path.join("a", "b", "s"))
4007+
4008+
with self.check_context(arc.open(), 'data'):
4009+
e = self.expect_exception(
4010+
tarfile.LinkFallbackError,
4011+
"link 's' would be extracted as a copy of "
4012+
+ "'a/b/s', which was rejected")
4013+
self.assertIsInstance(e.__cause__,
4014+
tarfile.LinkOutsideDestinationError)
4015+
4016+
for filter in 'tar', 'fully_trusted':
4017+
with self.subTest(filter), self.check_context(arc.open(), filter):
4018+
if not os_helper.can_symlink():
4019+
self.expect_file("a/")
4020+
self.expect_file("a/b/")
4021+
else:
4022+
self.expect_file("a/b/s", symlink_to=os.path.join('..', 'escape'))
4023+
self.expect_file("s", symlink_to=os.path.join('..', 'escape'))
4024+
40014025
@symlink_test
40024026
def test_exfiltration_via_symlink(self):
40034027
# (CVE-2025-4138)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed an vulnerability in the :mod:`tarfile` ``data`` and ``tar`` extraction
2+
filters where crafted archives could create a symlink pointing outside the
3+
destination directory. This was a bypass of CVE-2025-4330.

0 commit comments

Comments
 (0)