@@ -1085,6 +1085,52 @@ def test_varlib_build_inconsistent_use_my_metrics_flags(self):
10851085 save_before_dump = True ,
10861086 )
10871087
1088+ def test_varlib_path_traversal_sanitized (self ):
1089+ """Test that path traversal in <variable-font> filename is sanitized.
1090+
1091+ Only the basename should be used.
1092+ """
1093+ self .temp_dir ()
1094+ ttx_dir = self .get_test_input ("master_ttx_interpolatable_ttf" )
1095+ ttf_dir = os .path .join (self .tempdir , "masters" )
1096+ os .makedirs (ttf_dir )
1097+ for path in self .get_file_list (ttx_dir , ".ttx" , "TestFamily-" ):
1098+ self .compile_font (path , ".ttf" , ttf_dir )
1099+
1100+ # Test path traversal: "../forbidden/evil.ttf" should become "evil.ttf"
1101+ ds_path = os .path .join (self .tempdir , "test.designspace" )
1102+ with open (ds_path , "w" , encoding = "utf-8" ) as f :
1103+ f .write ("""<?xml version='1.0' encoding='UTF-8'?>
1104+ <designspace format="5.0">
1105+ <axes>
1106+ <axis tag="wght" name="Weight" minimum="300" maximum="700" default="300"/>
1107+ </axes>
1108+ <sources>
1109+ <source filename="masters/TestFamily-Master0.ttf" name="Light">
1110+ <location><dimension name="Weight" xvalue="300"/></location>
1111+ </source>
1112+ <source filename="masters/TestFamily-Master2.ttf" name="Bold">
1113+ <location><dimension name="Weight" xvalue="700"/></location>
1114+ </source>
1115+ </sources>
1116+ <variable-fonts>
1117+ <variable-font name="TestFamily" filename="../forbidden/evil.ttf">
1118+ <axis-subsets>
1119+ <axis-subset name="Weight"/>
1120+ </axis-subsets>
1121+ </variable-font>
1122+ </variable-fonts>
1123+ </designspace>""" )
1124+
1125+ # Run without --output-dir (defaults to designspace directory)
1126+ varLib_main ([ds_path ])
1127+
1128+ # Verify file is in same directory as designspace and not in ../forbidden/
1129+ self .assertTrue (os .path .isfile (os .path .join (self .tempdir , "evil.ttf" )))
1130+ self .assertFalse (
1131+ os .path .exists (os .path .join (self .tempdir , ".." , "forbidden" , "evil.ttf" ))
1132+ )
1133+
10881134
10891135def test_load_masters_layerName_without_required_font ():
10901136 ds = DesignSpaceDocument ()
0 commit comments