By Sanidhya Soni | February 01, 2026
Affected: FPDF ≤ 1.86
Vector: Remote code execution
Severity: High
Exploit prerequisites: The target application must allow an attacker to influence the file path passed to AddFont() (commonly via “custom font upload” features)
Summary
FPDF font definition files are PHP and are loaded using include(). If an application allows untrusted uploads to become font definition files, or allows attacker control of the path passed into AddFont(), the attacker can execute PHP. This is an insecure integration pattern, not a vulnerability in FPDF’s default behavior.
Background: how FPDF fonts are supposed to work
Instead of parsing .ttf files directly, FPDF uses a preprocessing step to generate PHP code that defines font metrics (like widths, heights, bounding box, etc.) pre-calculated in arrays.
When you add a font in FPDF, it executes a helper script to load these variables into memory.
This design creates a dangerous trust issue: If you incorrectly treat a user-uploaded .php as a font definition file, and that file happens to contain malicious code (like a web shell), it will be executed by the include() function.
Root cause
AddFont() forwards a path to _loadfont()
FPDF exposes AddFont() as the public entry point. In v1.86, this logic lives in fpdf.php around lines 443–461.
function AddFont($family, $style='', $file='', $dir='')
{
if(strpos($file,'/')!==false || strpos($file,"\\")!==false)
$this->Error('Incorrect font definition file name: '.$file);
if($dir=='')
$dir = $this->fontpath;
if(substr($dir,-1)!='/' && substr($dir,-1)!='\\')
$dir .= '/';
$info = $this->_loadfont($dir.$file); // Caller-supplied directory + file path; safe only if caller ensures it points to trusted font definition files.
}
_loadfont()
The core issue is FPDF loads font definition PHP via include(). It is safe only when loading trusted, developer-generated font definition files.
// Load a font definition file
protected function _loadfont($path)
{
include($path); // EXECUTES ARBITRARY PHP CODE!
if(!isset($name))
$this->Error('Could not include font definition file: '.$path);
}
Exploitation scenario
FPDF alone is a library; exploitation depends on how it is integrated. A common pattern in SaaS/invoicing/reporting tools is a “custom branding” feature, where users can upload fonts for document generation.
Common unsafe integration patterns
Custom font upload used directly by AddFont()
The application accepts a “.php” upload and later calls
AddFont()using the uploaded path.Attacker-influenced
$dir/ misconfiguredfontpathEven when
$fileis constrained to a basename, a controllable$dir(orfontpath) can redirect font loading to an attacker-writable directory.Auto-loading fonts from a writable directory
The application scans a fonts directory and calls
AddFont()on discovered files, but that directory is writable by users/tenants.
A typical vulnerable chain will look like:
The application provides a font upload feature (“upload .php”).
The upload is stored on disk (e.g.,
uploads/fonts/<user>/foo.php).The application later calls:
$pdf->AddFont('Foo', '', 'uploads/fonts/<user>/foo.php');FPDF calls
_loadfont()which doesinclude('uploads/.../foo.php').
If the stored file contains PHP code (e.g., <?php ... ?>), it will be executed.
Proof of Concept
Any file that reaches include() and contains PHP tags is sufficient. A minimal PoC could be:
<?php
// Required FPDF font definition variables
$name = 'EvilFont';
$type = 'TrueType';
$desc = array('Flags'=>32,'FontBBox'=>'[-665 -325 2000 1006]','ItalicAngle'=>0);
$up = -100;
$ut = 50;
$cw = array(chr(32)=>250,chr(65)=>722,chr(97)=>444);
//code execution
system("id; uname -a");
?>
Mitigation
Best addressed at the application boundary:
- Do not pass user-controlled paths to
AddFont() - If “custom fonts” are a hard requirement, Don’t feed uploads into
AddFont()directly.- Generate the font definition yourself using trusted tooling (
makefont.php) and store outputs in a controlled directory. - Enforce that only expected definition files (not arbitrary uploads) reach
_loadfont().
- Generate the font definition yourself using trusted tooling (
Timeline
- 2025-11-14 — Vulnerability discovered
- 2025-11-15 — Reported to CVE Assignment Team
- 2025-12-05 — CVE-2025-65875 assigned
- 2026-02-01 — Public disclosure
References
- FPDF Official: http://www.fpdf.org/
- FPDF GitHub: https://github.com/Setasign/FPDF
- PHP
include()Documentation: https://www.php.net/manual/en/function.include.php