GHSA-H5FH-7HWR-97MW

Vulnerability from github – Published: 2026-05-08 22:22 – Updated: 2026-05-08 22:22
VLAI
Summary
Kimai has an arbitrary file read in its invoice PDF renderer (admin)
Details

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

  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 associated_files in the pass-through allowlist: php $allowed = ['mode','format','default_font_size','default_font', ... , 'associated_files','additional_xmp_rdf']; and then forwards it to mPDF: php if (array_key_exists('associated_files', $options) && is_array($options['associated_files'])) { $associatedFiles = $options['associated_files']; unset($options['associated_files']); } ... $mpdf->SetAssociatedFiles($associatedFiles);

  3. mPDF 8.3.1 MetadataWriter::writeAssociatedFiles() calls file_get_contents, which respects PHP stream wrappers: ```php if (isset($file['path'])) { $fileContent = @file_get_contents($file['path']); } ... $filestream = gzcompress($fileContent); $this->writer->write('<

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 2.55"
      },
      "package": {
        "ecosystem": "Packagist",
        "name": "kimai/kimai"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.32.0"
            },
            {
              "fixed": "2.56"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-44298"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-08T22:22:36Z",
    "nvd_published_at": "2026-05-08T04:16:24Z",
    "severity": "MODERATE"
  },
  "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(\u0027associated_files\u0027, ...)` inside the sandboxed Twig render. \n\nThis is forwarded to mPDF\u0027s `SetAssociatedFiles()`, whose writer calls `file_get_contents($entry[\u0027path\u0027])` 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 !== \u0027setoption\u0027) { throw ...; }\n       return;\n   }\n   ```\n\n2. `src/Pdf/MPdfConverter.php` keeps `associated_files` in the pass-through allowlist:\n   ```php\n   $allowed = [\u0027mode\u0027,\u0027format\u0027,\u0027default_font_size\u0027,\u0027default_font\u0027, ... , \u0027associated_files\u0027,\u0027additional_xmp_rdf\u0027];\n   ```\n   and then forwards it to mPDF:\n   ```php\n   if (array_key_exists(\u0027associated_files\u0027, $options) \u0026\u0026 is_array($options[\u0027associated_files\u0027])) {\n       $associatedFiles = $options[\u0027associated_files\u0027];\n       unset($options[\u0027associated_files\u0027]);\n   }\n   ...\n   $mpdf-\u003eSetAssociatedFiles($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[\u0027path\u0027])) {\n       $fileContent = @file_get_contents($file[\u0027path\u0027]);\n   }\n   ...\n   $filestream = gzcompress($fileContent);\n   $this-\u003ewriter-\u003ewrite(\u0027\u003c\u003c/Type /EmbeddedFile\u0027);\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) \u003e 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(\u0027path\u0027, $entry)) {\n                    unset($entry[\u0027path\u0027]);\n                }\n\n                return $entry;\n            }, $associatedFiles);\n            $mpdf-\u003eSetAssociatedFiles($associatedFiles);\n        }\n\n```",
  "id": "GHSA-h5fh-7hwr-97mw",
  "modified": "2026-05-08T22:22:37Z",
  "published": "2026-05-08T22:22:36Z",
  "references": [
    {
      "type": "WEB",
      "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"
    },
    {
      "type": "WEB",
      "url": "https://github.com/kimai/kimai/releases/tag/2.56.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Kimai has an arbitrary file read in its invoice PDF renderer (admin)"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…