@@ -3987,6 +3987,29 @@ def test_sneaky_hardlink_fallback(self):
39873987 self .expect_file ("boom" , symlink_to = '../../link_here' )
39883988 self .expect_file ("c" , symlink_to = 'b' )
39893989
3990+ def test_sneaky_hardlink_fallback_deep (self ):
3991+ # (CVE-2026-11940)
3992+ with ArchiveMaker () as arc :
3993+ arc .add ("a/b/s" , symlink_to = os .path .join (".." , "escape" ))
3994+ arc .add ("s" , hardlink_to = os .path .join ("a" , "b" , "s" ))
3995+
3996+ with self .check_context (arc .open (), 'data' ):
3997+ e = self .expect_exception (
3998+ tarfile .LinkFallbackError ,
3999+ "link 's' would be extracted as a copy of "
4000+ + "'a/b/s', which was rejected" )
4001+ self .assertIsInstance (e .__cause__ ,
4002+ tarfile .LinkOutsideDestinationError )
4003+
4004+ for filter in 'tar' , 'fully_trusted' :
4005+ with self .subTest (filter ), self .check_context (arc .open (), filter ):
4006+ if not os_helper .can_symlink ():
4007+ self .expect_file ("a/" )
4008+ self .expect_file ("a/b/" )
4009+ else :
4010+ self .expect_file ("a/b/s" , symlink_to = os .path .join ('..' , 'escape' ))
4011+ self .expect_file ("s" , symlink_to = os .path .join ('..' , 'escape' ))
4012+
39904013 def test_exfiltration_via_symlink (self ):
39914014 # (CVE-2025-4138)
39924015 # Test changing symlinks that result in a symlink pointing outside
0 commit comments