{"id":"CVE-2026-44298","aliases":["GHSA-h5fh-7hwr-97mw"],"url":"https://o3.security/vulnerability/CVE-2026-44298","summary":"Kimai: Arbitrary file read in invoice PDF renderer (admin)","details":"## Summary\n\nUsers 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. \n\nThis 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.\n\n## Root cause\n\n1. `src/Twig/SecurityPolicy/StrictPolicy.php:123-128` explicitly whitelists `PdfContext::setOption()`:\n   ```php\n   if ($obj instanceof PdfContext) {\n       if ($lcm !== 'setoption') { throw ...; }\n       return;\n   }\n   ```\n\n2. `src/Pdf/MPdfConverter.php` keeps `associated_files` in the pass-through allowlist:\n   ```php\n   $allowed = ['mode','format','default_font_size','default_font', ... , 'associated_files','additional_xmp_rdf'];\n   ```\n   and then forwards it to mPDF:\n   ```php\n   if (array_key_exists('associated_files', $options) && is_array($options['associated_files'])) {\n       $associatedFiles = $options['associated_files'];\n       unset($options['associated_files']);\n   }\n   ...\n   $mpdf->SetAssociatedFiles($associatedFiles);\n   ```\n\n3. mPDF 8.3.1 `MetadataWriter::writeAssociatedFiles()` calls `file_get_contents`, which respects PHP stream wrappers:\n   ```php\n   if (isset($file['path'])) {\n       $fileContent = @file_get_contents($file['path']);\n   }\n   ...\n   $filestream = gzcompress($fileContent);\n   $this->writer->write('<</Type /EmbeddedFile');\n   ```\n\nThe 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.\n\n## Fix\n\nThe implemented fix has two aspects:\n\n1. The `PdfContext` now works with a strict allow-list, that excludes `associated_files`\n2. The `MPdfConverter` now removes any `path` from the `$associatedFiles` array, which can still be used by plugins:\n```php\n        if (\\count($associatedFiles) > 0) {\n            // remove \"path\" so mPDF will not use file_get_contents() on local files\n            // callers must pre-read and pass the bytes via \"content\"\n            $associatedFiles = array_map(static function ($entry): array {\n                if (!\\is_array($entry)) {\n                    return [];\n                }\n\n                if (\\array_key_exists('path', $entry)) {\n                    unset($entry['path']);\n                }\n\n                return $entry;\n            }, $associatedFiles);\n            $mpdf->SetAssociatedFiles($associatedFiles);\n        }\n\n```","published":"2026-05-08T03:32:06.672Z","modified":"2026-08-12T03:51:12.497810585Z","cvss":{"score":4.1,"severity":"MEDIUM","vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N"},"epss":{"score":0.00278,"percentile":0.19729,"asOf":"2026-08-24"},"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"Packagist","name":"kimai/kimai","fixedVersion":"2.56"}],"fix":null,"references":[{"type":"WEB","url":"https://github.com/kimai/kimai/releases/tag/2.56.0"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/44xxx/CVE-2026-44298.json"},{"type":"ADVISORY","url":"https://github.com/kimai/kimai/security/advisories/GHSA-h5fh-7hwr-97mw"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-44298"},{"type":"PACKAGE","url":"https://github.com/kimai/kimai"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-12T03:51:12.497810585Z"}}