highCVE-2026-52827Jul 14, 2026

CVE-2026-52827: Kimai 2FA TOTP Bypass via Pre-Verification Session Cookie

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

Kimai's REST API accepts the session cookie issued right after password entry, before the TOTP step is completed, letting an attacker with only a password skip two-factor authentication entirely.

Packagekimai/kimai
Ecosystemcomposer
Affected< 2.59.0
Fixed in2.59.0

The problem

Every `/api/*` endpoint in Kimai accepted the `KIMAI_SESSION` cookie produced at the end of the password-check step, before the user ever sees the TOTP prompt.

The Symfony security firewall guarded the API with `IS_AUTHENTICATED`, and the Scheb `TwoFactorToken` in the session satisfies that check because it is a real, non-anonymous token. `ApiRequestMatcher` also short-circuits the stateless firewall when a session is present, routing the request through the session-aware main firewall where the TOTP gate is never enforced.

The net result: any account with 2FA enabled can be fully accessed via the API with just the account password.

Proof of concept

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

bash
# Step 1: log in with password only, capture the session cookie
curl -i -c cookies.txt -X POST https://kimai.example.com/en/login \
  -d 'email=victim@example.com&password=s3cr3t&_csrf_token='
# The response sets KIMAI_SESSION even though the browser is held at /en/auth/2fa

# Step 2: replay the pre-2FA session cookie against any API endpoint
# TOTP code is never required
curl -s \
  -b cookies.txt \
  https://kimai.example.com/api/users/me

The root cause (CWE-287 Improper Authentication) is that `IS_AUTHENTICATED` in Symfony is satisfied by a `TwoFactorToken`, which the Scheb bundle places in the session immediately after password verification and before TOTP confirmation. The API firewall used this flag, so a mid-flow session cookie was treated as fully authenticated.

The patch tightens both layers. The `/api/` firewall now requires `IS_AUTHENTICATED_REMEMBERED`, which Scheb only assigns after 2FA completes. `ApiVoter` additionally checks `$token instanceof TwoFactorTokenInterface` and `isGranted('IS_AUTHENTICATED_2FA_IN_PROGRESS')`, refusing the `API` grant to any token still in the 2FA flow.

Regression tests were added to lock in the fix.

The fix

Upgrade to kimai/kimai 2.59.0 or later. No configuration change is required; the fix is in the firewall definition (`config/packages/security.yaml`) and in `App\Voter\ApiVoter`.

Reported by shafiqaimanx.

References: [1][2]

Related research