GitHub Security Advisory: GHSA-vrqv-52x7-rm4v
Package: kimai/kimai (COMPOSER)
Severity: MODERATE (CVSS 0.0)
CWE: CWE-693: Protection Mechanism Failure
Vulnerable versions: <= 2.55.0
Patched in: 2.56.0

Summary: Kimai's Twig function config() leaks server-wide secrets (LDAP bind password, SAML SP private key) via invoice/export templates

Details:
### 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 pa