Skip to content

Commit b00bc45

Browse files
committed
varLib_test: test path traversal in variable-font filename
Reproduces GHSA-768j-98cg-p3fv
1 parent 066512e commit b00bc45

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

Tests/varLib/varLib_test.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

10891135
def test_load_masters_layerName_without_required_font():
10901136
ds = DesignSpaceDocument()

0 commit comments

Comments
 (0)