CVE-2026-44298: Kimai: Arbitrary file read in invoice PDF renderer (admin)
Summary
Users with the role System-Admin (ROLESYSTEADMIN) and the permission uploadinvoicetemplate can upload PDF invoice templates, which can call pdfContext.setOption('associatedfiles', ...) inside the sandboxed Twig render.
This is forwarded to mPDF's SetAssociatedFiles(), whose writer calls filegetcontents($entry['path']) during PDF output and embeds the bytes as a FlateDecode stream in the PDF. Any file readable by the PHP worker is returned to the attacker inside the rendered invoice.
Root cause
1. src/Twig/SecurityPolicy/StrictPolicy.php:123-128 explicitly whitelists PdfContext::setOption(): php if ($obj instanceof PdfContext) { if ($lcm !== 'setoption') { throw ...; } return; }
2. src/Pdf/MPdfConverter.php keeps associatedfiles in the pass-through allowlist: php $allowed = ['mode','format','defaultfontsize','defaultfont', ... , 'associatedfiles','additionalxmprdf']; and then forwards it to mPDF: php if (arraykeyexists('associatedfiles', $options) && isarray($options['associatedfiles'])) { $associatedFiles = $options['associatedfiles']; unset($options['associatedfiles']); } ... $mpdf->SetAssociatedFiles($associatedFiles);
3. mPDF 8.3.1 MetadataWriter::writeAssociatedFiles() calls filegetcontents, which respects PHP stream wrappers: php if (isset($file['path'])) { $fileContent = @filegetcontents($file['path']); } ... $filestream = gzcompress($fileContent); $this->writer->write('<</Type /EmbeddedFile');
The sandbox and the option allowlist were both written defensively (short whitelists, not blacklists), but neither side considered that associatedfiles is a PDF/A file-embedding feature whose path key is a sink.
Fix
The implemented fix has two aspects:
1. The PdfContext now works with a strict allow-list, that excludes associatedfiles 2. The MPdfConverter now removes any path from the $associatedFiles array, which can still be used by plugins: php if (\count($associatedFiles) > 0) { // remove "path" so mPDF will not use filegetcontents() on local files // callers must pre-read and pass the bytes via "content" $associatedFiles = arraymap(static function ($entry): array { if (!\isarray($entry)) { return []; }
if (\arraykeyexists('path', $entry)) { unset($entry['path']); }
return $entry; }, $associatedFiles); $mpdf->SetAssociatedFiles($associatedFiles); }
Other sources
Kimai is an open-source time tracking application. From version 2.32.0 to before version 2.56.0, users with the role System-Admin (ROLESYSTEADMIN) and the permission uploadinvoicetemplate can upload PDF invoice templates, which can call pdfContext.setOption('associatedfiles', ...) inside the sandboxed Twig render. This is forwarded to mPDF's SetAssociatedFiles(), whose writer calls filegetcontents($entry['path']) during PDF output and embeds the bytes as a FlateDecode stream in the PDF. Any file readable by the PHP worker is returned to the attacker inside the rendered invoice. This issue has been patched in version 2.56.0.
— MITRE
Affected Software
Event History
Frequently Asked Questions
What is the severity of CVE-2026-44298?
CVE-2026-44298 is considered to have a high severity rating due to the potential for arbitrary file reading by users with admin privileges.
How do I fix CVE-2026-44298?
To mitigate CVE-2026-44298, upgrade Kimai to version 2.56.0 or later to eliminate the vulnerability.
Who is affected by CVE-2026-44298?
CVE-2026-44298 affects all users of Kimai versions 2.32.0 to before 2.56.0 with the System-Admin role and the necessary permissions.
What specific feature is exploited in CVE-2026-44298?
CVE-2026-44298 exploits the invoice PDF renderer feature, allowing unauthorized file access through uploaded templates.
What types of files can be read due to CVE-2026-44298?
Due to CVE-2026-44298, an attacker could potentially read any file accessible by the server, depending on the implementation of the uploaded PDF invoice templates.