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…

Detection rules are retrieved from Rulezet.

Loading…

Loading…