@@ -4344,6 +4344,30 @@ def test_sneaky_hardlink_fallback(self):
43444344 self .expect_file ("boom" , symlink_to = '../../link_here' )
43454345 self .expect_file ("c" , symlink_to = 'b' )
43464346
4347+ @symlink_test
4348+ def test_sneaky_hardlink_fallback_deep (self ):
4349+ # (CVE-2026-11940)
4350+ with ArchiveMaker () as arc :
4351+ arc .add ("a/b/s" , symlink_to = os .path .join (".." , "escape" ))
4352+ arc .add ("s" , hardlink_to = os .path .join ("a" , "b" , "s" ))
4353+
4354+ with self .check_context (arc .open (), 'data' ):
4355+ e = self .expect_exception (
4356+ tarfile .LinkFallbackError ,
4357+ "link 's' would be extracted as a copy of "
4358+ + "'a/b/s', which was rejected" )
4359+ self .assertIsInstance (e .__cause__ ,
4360+ tarfile .LinkOutsideDestinationError )
4361+
4362+ for filter in 'tar' , 'fully_trusted' :
4363+ with self .subTest (filter ), self .check_context (arc .open (), filter ):
4364+ if not os_helper .can_symlink ():
4365+ self .expect_file ("a/" )
4366+ self .expect_file ("a/b/" )
4367+ else :
4368+ self .expect_file ("a/b/s" , symlink_to = os .path .join ('..' , 'escape' ))
4369+ self .expect_file ("s" , symlink_to = os .path .join ('..' , 'escape' ))
4370+
43474371 @symlink_test
43484372 def test_exfiltration_via_symlink (self ):
43494373 # (CVE-2025-4138)
0 commit comments