Kimai has an arbitrary file read in its invoice PDF renderer (admin)
Summary
Users with the role System-Admin (ROLE_SYSTE_ADMIN) and the permission upload_invoice_template can upload PDF invoice templates, which can call pdfContext.setOption('associated_files', ...) inside the sandboxed Twig render.
This is forwarded to mPDF's SetAssociatedFiles(), whose writer calls file_get_contents($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
-
src/Twig/SecurityPolicy/StrictPolicy.php:123-128explicitly whitelistsPdfContext::setOption():phpif ($obj instanceof PdfContext) { if ($lcm !== 'setoption') { throw ...; } return; } -
src/Pdf/MPdfConverter.phpkeepsassociated_filesin the pass-through allowlist:php$allowed = ['mode','format','default_font_size','default_font', ... , 'associated_files','additional_xmp_rdf'];and then forwards it to mPDF:
phpif (array_key_exists('associated_files', $options) && is_array($options['associated_files'])) { $associatedFiles = $options['associated_files']; unset($options['associated_files']); } ... $mpdf->SetAssociatedFiles($associatedFiles); -
mPDF 8.3.1
MetadataWriter::writeAssociatedFiles()callsfile_get_contents, which respects PHP stream wrappers:phpif (isset($file['path'])) { $fileContent = @file_get_contents($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 associated_files is a PDF/A file-embedding feature whose path key is a sink.
Fix
The implemented fix has two aspects:
- The
PdfContextnow works with a strict allow-list, that excludesassociated_files - The
MPdfConverternow removes anypathfrom the$associatedFilesarray, which can still be used by plugins:
if (\count($associatedFiles) > 0) {
// remove "path" so mPDF will not use file_get_contents() on local files
// callers must pre-read and pass the bytes via "content"
$associatedFiles = array_map(static function ($entry): array {
if (!\is_array($entry)) {
return [];
}
if (\array_key_exists('path', $entry)) {
unset($entry['path']);
}
return $entry;
}, $associatedFiles);
$mpdf->SetAssociatedFiles($associatedFiles);
}
Betroffene Software
Klicken Sie auf eine Technologie, um alle zugehörigen Schwachstellen anzuzeigen.
| Plattform | Paket | Anfällige Versionen | Behoben in |
|---|---|---|---|
| Composer-Paket | kimai/kimai | >= 2.32.0, < 2.56 | 2.56 |
Verweise
- CVSS-Vektor
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N- Schwäche (CWE)
CWE-22- Plattform
- Composer
- Paket
kimai/kimai- Veröffentlicht
- 08.05.2026
- Aktualisiert
- 11.10.2026 10:22
Quellen und Lizenzen
OSV / GitHub Advisory Database - GHSA-h5fh-7hwr-97mw - CC BY 4.0
Schwachstellenhistorie: kimai/kimai
Alle veröffentlichten Schwachstellen dieses Pakets (Composer-Paket), neueste zuerst. Zeigt, ob es ein einmaliger Ausrutscher ist oder ein Paket, das man im Auge behalten muss.
- Einträge insgesamt
- 33
- Erste → letzte
- 02.2023 07.2026
- Ohne Fix
- 1
- In Angriffen ausgenutzt
- 0
Verteilung nach Schweregrad
- Kritisch 2
- Hoch 4
- Mittel 20
- Niedrig 7
Veröffentlichungen pro Jahr
- 2023: 2
- 2024: 3
- 2025: 1
- 2026: 27
-
Kimai has an arbitrary file read in its invoice PDF renderer (admin) dieser Eintrag
Erkennen Sie Schwachstellen in Ihrer Anwendung
Mit der DockRay-Integration und aktivierter Softwareinventarisierung prüft DockRay gemeldete Komponentenversionen auf bekannte Schwachstellen und benachrichtigt Sie über bestätigte Treffer. Die Abdeckung hängt von der unterstützten Technologie und den verfügbaren Meldungen ab.