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:

  1. Path Traversal: Write font output to any filesystem path
  2. 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 write

os.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 filename attribute causes os.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.