Affected Version
11.x, 2025.x, 2026.x
Affected capability
Core
Steps to reproduce
- Fresh Pimcore 11 (tested on 11.5.8, code unchanged up to 11.5.14.1 and 2026.2.1) with:
pimcore:
full_page_cache:
enabled: true
- APP_DEBUG=0, debug mode off, any frontend firewall with lazy sessions (Symfony default).
- Warm the cache anonymously and confirm the cache hit:
curl -sI https://example.test/en | grep -i x-pimcore
2nd call → x-pimcore-output-cache-tag: output_...
- Create a session that contains data — e.g. log in through a frontend firewall, or hit any controller that writes to the session.
- Request the same URL with that session cookie:
curl -sI -H "Cookie: PHPSESSID=" https://example.test/en | grep -i x-pimcore
Actual Behavior
$sessionData = $_SESSION ?? null;
if (!$sessionData) {
return false; // always taken on cache hits — session was never started
}
The session-ID guard above it passes (Symfony's AbstractSessionListener copies the ID from the cookie without starting the session), but the session data is never loaded from the handler. The listener then sets the cached response and stops propagation, so the firewall never runs at all.
The check works correctly on the store side (onKernelResponse, session started by then) — personalized responses are kept out of the cache. Only the delivery side is blind. Note that two lines below the session check, Tool\Authentication::authenticateSession() does start the session (via $session->get()) to detect admin users - so the admin check works while the frontend session check right before it never can.
Impact: on sites where publicly cacheable pages render session-dependent content (login state in the header, customer-specific prices), logged-in users receive the anonymous cached copy. With an SSO/OIDC login this produces an endless login loop: user logs in → served the anonymous cached page → appears logged out → clicks login → SSO signs in instantly → same cached page again.
Expected Behavior
A request carrying a session with data is not answered from the full page cache — the response should carry x-pimcore-output-cache-disable-reason: Session in use, matching what SessionStatus::isDisabledBySession() clearly intends to do.
Suggested fix — start the session before inspecting it, when the request carries a session cookie:
if ($request->hasPreviousSession()) {
$session = $request->getSession();
if (!$session->isStarted()) {
$session->start();
}
}
This costs one session-handler read only for requests presenting a session cookie and keeps cache hits for visitors with empty sessions (unlike the exclude_cookie workaround, which sacrifices all of them). We run this as a service override of Pimcore\Cache\FullPage\SessionStatus in production and can confirm it resolves the issue. Alternative: reorder the checks so Tool\Authentication::authenticateSession() (which starts the session anyway)runs first — or document that isDisabledBySession() cannot detect sessions on cache hits and exclude_cookie is required for session-dependent public pages.
Affected Version
11.x, 2025.x, 2026.x
Affected capability
Core
Steps to reproduce
curl -sI https://example.test/en | grep -i x-pimcore2nd call →
x-pimcore-output-cache-tag: output_...curl -sI -H "Cookie: PHPSESSID=" https://example.test/en | grep -i x-pimcore
Actual Behavior
The session-ID guard above it passes (Symfony's AbstractSessionListener copies the ID from the cookie without starting the session), but the session data is never loaded from the handler. The listener then sets the cached response and stops propagation, so the firewall never runs at all.
The check works correctly on the store side (onKernelResponse, session started by then) — personalized responses are kept out of the cache. Only the delivery side is blind. Note that two lines below the session check,
Tool\Authentication::authenticateSession()does start the session (via$session->get()) to detect admin users - so the admin check works while the frontend session check right before it never can.Impact: on sites where publicly cacheable pages render session-dependent content (login state in the header, customer-specific prices), logged-in users receive the anonymous cached copy. With an SSO/OIDC login this produces an endless login loop: user logs in → served the anonymous cached page → appears logged out → clicks login → SSO signs in instantly → same cached page again.
Expected Behavior
A request carrying a session with data is not answered from the full page cache — the response should carry
x-pimcore-output-cache-disable-reason: Session in use, matching what SessionStatus::isDisabledBySession() clearly intends to do.Suggested fix — start the session before inspecting it, when the request carries a session cookie:
This costs one session-handler read only for requests presenting a session cookie and keeps cache hits for visitors with empty sessions (unlike the
exclude_cookieworkaround, which sacrifices all of them). We run this as a service override ofPimcore\Cache\FullPage\SessionStatusin production and can confirm it resolves the issue. Alternative: reorder the checks soTool\Authentication::authenticateSession()(which starts the session anyway)runs first — or document that isDisabledBySession() cannot detect sessions on cache hits andexclude_cookieis required for session-dependent public pages.