Vulnerability Summary
fonttools (fontTools.varLib) is vulnerable to arbitrary file write and XML injection when processing a malicious .designspace file. github Two distinct weaknesses chain together:
- Path Traversal: Write font output to any filesystem path
- XML Injection: Inject arbitrary content (e.g. PHP) into the written file
Chained together → RCE if the written file lands in a web-accessible directory.
Root Cause
The vulnerable lines in fontTools/varLib/__init__.py:
filename = vf.filename # Unsanitised — attacker-controlled from .designspace
output_path = os.path.join(output_dir, filename) # Path traversal
vf.save(output_path) # Arbitrary writeos.path.join with a path like ../../tmp/evil.php walks right out of the intended output directory. No sanitization, no os.path.basename() enforcement.
Affected Versions
fonttools >= 4.33.0, < 4.60.2 — patched in 4.60.2.
Exploitation
A summarized code for reverse shell can be found on my github.
The script automates the full chain — font generation, malicious .designspace crafting, upload, and reverse shell delivery. Two primitives are chained in a single upload:
- The CDATA split in
<labelname>embeds raw PHP into the output font binary, bypassing the XML parser - An absolute path in the
filenameattribute causesos.path.join()to discard the intended output directory entirely, writing the shell directly to the web root
Once the server processes the upload, a single HTTP GET to the written file triggers execution and connects back to a waiting listener.
Fix
The patch in 4.60.2 is a one-liner — enforcing os.path.basename() on the filename before constructing the output path, stripping any directory traversal sequences regardless of what the .designspace contains.