GHSA-vrqv-52x7-rm4v: Kimai/kimai Kimai's Twig Function Config() Leaks Vulnerability

MODERATE
CWE-693
Published
Advisory Summary

GHSA-vrqv-52x7-rm4v is a MODERATE kimai's twig function config() leaks vulnerability (CWE-693: Protection Mechanism Failure) affecting Kimai/kimai libraries in the Packagist ecosystem. The issue involves kimai's twig function config() leaks server-wide secrets (ldap bind password, saml sp private key) via invoice/export templates. Remediation is available by upgrading affected packages to version 2.56.0.

GHSA-vrqv-52x7-rm4v at a Glance

CVE Identifier N/A
GHSA Identifier GHSA-vrqv-52x7-rm4v
Severity MODERATE
CVSS v3.1 Base Score N/A
CWE Classification CWE-693: Protection Mechanism Failure
Affected Product Kimai/kimai
Package Ecosystem Packagist
Published Date
Last Updated

How to Fix GHSA-vrqv-52x7-rm4v

To remediate this vulnerability, upgrade all affected Kimai/kimai dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

kimai/kimai fixed: 2.56.0
Upgrade kimai/kimai to 2.56.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for kimai/kimai

How to Check if You Are Affected

To determine whether your application is affected by GHSA-vrqv-52x7-rm4v, inspect your project dependencies for Kimai/kimai:

inspect dependencies for kimai/kimai

Analyze the terminal output to locate any version of Kimai/kimai in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2.56.0), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-693: Protection Mechanism Failure, where the product does not use or incorrectly uses a protection mechanism that provides sufficient defense against directed attacks against the product. In Kimai/kimai, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### Summary Kimai'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. ### Details `src/Twig/SecurityPolicy/StrictPolicy.php:40-55` explicitly allow-lists `'config'`: ```php private array $allowedFunctions = [ 'max', 'min', 'range', 'constant', 'cycle', 'random', 'date', 't', 'encore_entry_css_source', 'encore_entry_link_tags', 'encore_entry_script_tags', 'is_granted', 'qr_code_data_uri', 'config', // <-- sink, no key filter 'create_date', 'month_names', 'locale_format', 'class_name' ]; ``` `src/Twig/Configuration.php:22-45` is the Twig function implementation: ```php public function getFunctions(): array { return [new TwigFunction('config', [$this, 'get'])]; } public function get(string $name) { switch ($name) { case 'chart-class': return ''; case 'theme.chart.background_color': return '#3c8dbc'; // ... 4 more theme constants } return $this->configuration->find($name); // <-- arbitrary key lookup } ``` `App\Configuration\SystemConfiguration::find()` at `src/Configuration/SystemConfiguration.php:54-62` is a direct dictionary lookup. The dictionary `$this->settings` is initialised from the `kimai.config` container parameter, which the `AppExtension` flattens from `kimai.yaml` into dotted-notation keys. ``` The LDAP and SAML schemas declared in `src/DependencyInjection/Configuration.php` define secret-valued scalar nodes that survive the flattening and become reachable keys: ```php // getLdapNode() ->arrayNode('connection') ->children() ->scalarNode('host')->defaultNull()->end() ->scalarNode('username')->end() ->scalarNode('password')->end() // -> settings['ldap.connection.password'] ... // getSamlNode() ->arrayNode('sp') ->children() ->scalarNode('x509cert')->end() ->scalarNode('privateKey')->end() // -> settings['saml.connection.sp.privateKey'] ... ``` The 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`. In 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. ### Impact Any 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. ### Solution The `config()` function was patched to only return a pre-configured list of settings in sandboxed mode. Additional checks were added to prevent access to configs that start with `saml.` or `ldap.`. Kimai 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.

GHSA-vrqv-52x7-rm4v Affected Kimai/kimai Versions

1 component(s)
Fixed Versions:
2.56.0
Product / Package Ecosystem Affected Versions Fixed Version
kimai/kimai
Packagist
< 2.56.0
2.56.0

References

Frequently Asked Questions

What is GHSA-vrqv-52x7-rm4v?
GHSA-vrqv-52x7-rm4v is a security vulnerability in Kimai/kimai involving Kimai's Twig function config() leaks server-wide secrets (LDAP bind password, SAML SP private key) via invoice/export templates under CWE-693: Protection Mechanism Failure.
Which Kimai/kimai versions are affected?
Affected versions include releases prior to 2.56.0 across affected packages: kimai/kimai.
What version fixes GHSA-vrqv-52x7-rm4v?
Upgrading to 2.56.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is kimai/kimai affected?
Yes, kimai/kimai is affected in releases prior to 2.56.0. Upgrade your dependency to 2.56.0 or later.
What CWE is associated with GHSA-vrqv-52x7-rm4v?
GHSA-vrqv-52x7-rm4v is classified under CWE-693: Protection Mechanism Failure (The product does not use or incorrectly uses a protection mechanism that provides sufficient defense against directed attacks against the product.).
How can I check Packagist dependencies for GHSA-vrqv-52x7-rm4v?
Run the dependency tree command: 'inspect dependencies for kimai/kimai'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-vrqv-52x7-rm4v",
  "modified" : "2026-05-06T18:42:30Z",
  "published" : "2026-05-06T18:42:30Z",
  "aliases" : [ ],
  "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',                       // <-- 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->configuration->find($name);   // <-- 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->settings` 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->arrayNode('connection')\n    ->children()\n        ->scalarNode('host')->defaultNull()->end()\n        ->scalarNode('username')->end()\n        ->scalarNode('password')->end()       // -> settings['ldap.connection.password']\n        ...\n\n// getSamlNode()\n->arrayNode('sp')\n    ->children()\n        ->scalarNode('x509cert')->end()\n        ->scalarNode('privateKey')->end()     // -> 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.",
  "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"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "kimai/kimai"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "2.56.0"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 2.55.0"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/kimai/kimai/security/advisories/GHSA-vrqv-52x7-rm4v"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/kimai/kimai"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-693" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-05-06T18:42:30Z",
    "nvd_published_at" : null
  }
}