{"id":"GHSA-vrqv-52x7-rm4v","summary":"Kimai's Twig function config() leaks server-wide secrets (LDAP bind password, SAML SP private key) via invoice/export templates","details":"### Summary\n\nKimai's Twig sandbox (`StrictPolicy`, used for admin-uploaded invoice and export templates) allow-lists the `config()` Twig function with no key filtering. `config(name)` delegates to `App\\Configuration\\SystemConfiguration::find($name)`, which returns arbitrary entries from the flattened `kimai.config` container parameter built in `App\\DependencyInjection\\AppExtension::loadInternal()`. Any admin who can upload a Twig template can therefore render server-wide secrets - the LDAP bind password, the SAML SP private key, and any other dotted configuration key populated from `kimai.yaml` - into the invoice or export output, which is then delivered to whoever generates an invoice or export from that template (including lower-privileged users such as teamleads with invoice permissions). This is a second, uncovered class of the same defense-in-depth issue patched in GHSA-rh42-6rj2-xwmc: the previous fix added a User-method blocklist but left the `config()` function unrestricted.\n\n### Details\n\n`src/Twig/SecurityPolicy/StrictPolicy.php:40-55` explicitly allow-lists `'config'`:\n\n```php\nprivate array $allowedFunctions = [\n    'max', 'min', 'range', 'constant', 'cycle', 'random', 'date',\n    't',\n    'encore_entry_css_source', 'encore_entry_link_tags', 'encore_entry_script_tags',\n    'is_granted',\n    'qr_code_data_uri',\n    'config',                       // \u003c-- sink, no key filter\n    'create_date', 'month_names', 'locale_format',\n    'class_name'\n];\n```\n\n`src/Twig/Configuration.php:22-45` is the Twig function implementation:\n\n```php\npublic function getFunctions(): array\n{\n    return [new TwigFunction('config', [$this, 'get'])];\n}\n\npublic function get(string $name)\n{\n    switch ($name) {\n        case 'chart-class':                     return '';\n        case 'theme.chart.background_color':    return '#3c8dbc';\n        // ... 4 more theme constants\n    }\n    return $this-\u003econfiguration-\u003efind($name);   // \u003c-- arbitrary key lookup\n}\n```\n\n`App\\Configuration\\SystemConfiguration::find()` at `src/Configuration/SystemConfiguration.php:54-62` is a direct dictionary lookup. The dictionary `$this-\u003esettings` is initialised from the `kimai.config` container parameter, which the `AppExtension` flattens from `kimai.yaml` into dotted-notation keys.\n```\n\nThe LDAP and SAML schemas declared in `src/DependencyInjection/Configuration.php` define secret-valued scalar nodes that survive the flattening and become reachable keys:\n\n```php\n// getLdapNode()\n-\u003earrayNode('connection')\n    -\u003echildren()\n        -\u003escalarNode('host')-\u003edefaultNull()-\u003eend()\n        -\u003escalarNode('username')-\u003eend()\n        -\u003escalarNode('password')-\u003eend()       // -\u003e settings['ldap.connection.password']\n        ...\n\n// getSamlNode()\n-\u003earrayNode('sp')\n    -\u003echildren()\n        -\u003escalarNode('x509cert')-\u003eend()\n        -\u003escalarNode('privateKey')-\u003eend()     // -\u003e settings['saml.connection.sp.privateKey']\n        ...\n```\n\nThe invoice and export renderers both enable the sandbox against `StrictPolicy` and pass the shared Twig environment - the one with the `config` function registered - into sandboxed rendering: `src/Invoice/Renderer/AbstractTwigRenderer.php:66-74` and `src/Export/Base/{PDFRenderer,HtmlRenderer}.php`. An admin who uploads a malicious invoice or export template therefore gets an unrestricted read primitive against `kimai.config`.\n\nIn a real deployment the attacker template is uploaded through the admin UI (ROLE_SUPER_ADMIN, permission `upload_invoice_template`), saved by `src/Invoice/InvoiceTemplate*` and later rendered by whoever generates an invoice or export for that template. The rendering user is typically a teamlead or admin with invoice permission (`INVOICE` permission set: `['view_invoice','create_invoice','manage_invoice_template']`, granted to ROLE_ADMIN and ROLE_TEAMLEAD in `config/packages/kimai.yaml`). The rendered output is returned as the invoice PDF/HTML or as a CSV/XLSX export, so the secrets land in a document that is routinely downloaded and emailed.\n\n### Impact\n\nAny Kimai deployment that (a) has SAML or LDAP configured in `kimai.yaml`, and (b) has at least one user (other than the current SUPER_ADMIN) who will render a template-based invoice or export in the future, is affected. A malicious or compromised SUPER_ADMIN can upload a template once, leave, and subsequent invoice or export generations by teamleads or other admins silently exfiltrate `ldap.connection.password`, `saml.connection.sp.privateKey`, `saml.connection.sp.x509cert`, and any other dotted configuration key into an attacker-readable artifact. The LDAP bind password gives domain-credential access to the company directory and often to every downstream system that trusts the same directory; the SAML SP private key allows an attacker to forge signed SAML assertions to any service provider that trusts the same key pair. This is the same class of defense-in-depth leak that GHSA-rh42-6rj2-xwmc patched for user-level secrets, at a broader impact because the keys leaked here are system-wide rather than per-user, and the current StrictPolicy does not intercept the `config()` call path. \n\n### Solution\n\nThe `config()` function was patched to only return a pre-configured list of settings in sandboxed mode. \n\nAdditional checks were added to prevent access to configs that start with `saml.` or `ldap.`.\n\nKimai will not issue a CVE, because this requires a SUPER_ADMIN account and it only affects system with activated LDAP or SAML, which also uses the invoice system.","modified":"2026-05-06T18:51:21.811041Z","published":"2026-05-06T18:42:30Z","database_specific":{"nvd_published_at":null,"github_reviewed":true,"github_reviewed_at":"2026-05-06T18:42:30Z","severity":"MODERATE","cwe_ids":["CWE-693"]},"references":[{"type":"WEB","url":"https://github.com/kimai/kimai/security/advisories/GHSA-vrqv-52x7-rm4v"},{"type":"PACKAGE","url":"https://github.com/kimai/kimai"}],"affected":[{"package":{"name":"kimai/kimai","ecosystem":"Packagist","purl":"pkg:composer/kimai/kimai"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.56.0"}]}],"versions":["0.1","0.2","0.3","0.4","0.5","0.6","0.6.1","0.7","0.8","0.8.1","0.9","1.0","1.0.1","1.1","1.10","1.10.1","1.10.2","1.11","1.11.1","1.12","1.13","1.14","1.14.1","1.14.2","1.14.3","1.15","1.15.1","1.15.2","1.15.3","1.15.4","1.15.5","1.15.6","1.16","1.16.1","1.16.10","1.16.2","1.16.3","1.16.4","1.16.5","1.16.6","1.16.7","1.16.8","1.16.9","1.17","1.17.1","1.18","1.18.1","1.18.2","1.19","1.19.1","1.19.2","1.19.3","1.19.4","1.19.5","1.19.6","1.19.7","1.2","1.20","1.20.1","1.20.2","1.20.3","1.20.4","1.21.0","1.22.0","1.22.1","1.23.0","1.23.1","1.24.0","1.25.0","1.26.0","1.27.0","1.28.0","1.28.1","1.29.0","1.29.1","1.3","1.30.0","1.30.1","1.30.10","1.30.11","1.30.2","1.30.3","1.30.4","1.30.5","1.30.6","1.30.7","1.30.8","1.30.9","1.4","1.4.1","1.4.2","1.5","1.6","1.6.1","1.6.2","1.7","1.8","1.9","2.0.0","2.0.0-alpha","2.0.0-beta","2.0.0-beta-2","2.0.0-beta-3","2.0.0-rc-1","2.0.1","2.0.10","2.0.11","2.0.12","2.0.13","2.0.14","2.0.15","2.0.16","2.0.17","2.0.18","2.0.19","2.0.2","2.0.20","2.0.21","2.0.22","2.0.23","2.0.24","2.0.25","2.0.26","2.0.27","2.0.28","2.0.29","2.0.3","2.0.30","2.0.31","2.0.32","2.0.33","2.0.34","2.0.35","2.0.4","2.0.5","2.0.6","2.0.7","2.0.8","2.0.9","2.1.0","2.10.0","2.11.0","2.12.0","2.13.0","2.14.0","2.15.0","2.16.0","2.16.1","2.17.0","2.18.0","2.19.0","2.19.1","2.2.0","2.2.1","2.20.0","2.20.1","2.21.0","2.22.0","2.23.0","2.24.0","2.25.0","2.26.0","2.27.0","2.28.0","2.29.0","2.3.0","2.30.0","2.31.0","2.32.0","2.33.0","2.34.0","2.35.0","2.35.1","2.36.0","2.36.1","2.37.0","2.38.0","2.39.0","2.4.0","2.4.1","2.40.0","2.41.0","2.42.0","2.43.0","2.44.0","2.45.0","2.46.0","2.47.0","2.48.0","2.49.0","2.5.0","2.50.0","2.51.0","2.52.0","2.53.0","2.54.0","2.55.0","2.6.0","2.7.0","2.8.0","2.9.0"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-vrqv-52x7-rm4v/GHSA-vrqv-52x7-rm4v.json","last_known_affected_version_range":"\u003c= 2.55.0"}}],"schema_version":"1.7.5","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:P"}]}