From f2fa2e512a260808f4772a530fa21d143e58f39a Mon Sep 17 00:00:00 2001 From: "Beau Beauchamp, WebTigers" Date: Wed, 16 Sep 2026 04:58:30 -0400 Subject: [PATCH] 1.8.3: stale session cookie no longer 500s under the DB handler either 1.8.2 covered only the files handler. cPanel leaves session.use_strict_mode off, so any unknown client id is accepted; enable strict mode before start (PHP mints a fresh id), keep the unreadable-files guard, and retry once on a start exception. Verified live under both handlers. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01L8p9pLJ3DFstG3xZuh2QgZ --- CHANGELOG.md | 13 +++++++++++++ library/Tiger/Application/Bootstrap.php | 21 +++++++++++++++++++-- library/Tiger/Version.php | 2 +- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4f5395..c1cc6b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,19 @@ All notable changes to **Tiger Core** (`webtigers/tiger-core`). Format follows ## [Unreleased] +## [1.8.3] — 2026-09-16 + +### Fixed + +- **A stale session cookie 500'd the site under the DB session handler too** (1.8.2 covered only the + files handler). The real cause is broader: cPanel leaves PHP's `session.use_strict_mode` off, so a + client-supplied unknown session id is accepted as-is — the files handler then reads a foreign, + unreadable file, and either handler can leave a phantom id that a later `regenerateId()` rejects. + The bootstrap now enables `session.use_strict_mode` before starting (PHP mints a fresh id for any + unknown one, the standard defence), keeps the unreadable-files guard as a belt, and retries once + with a clean id if start still throws — so a returning visitor with any stale cookie is a guest, + never a 500. Verified on a live cPanel install under both the DB and files handlers (TIGER-138). + ## [1.8.2] — 2026-09-16 ### Fixed diff --git a/library/Tiger/Application/Bootstrap.php b/library/Tiger/Application/Bootstrap.php index f8bc65c..4a8605c 100644 --- a/library/Tiger/Application/Bootstrap.php +++ b/library/Tiger/Application/Bootstrap.php @@ -662,8 +662,25 @@ protected function _initSession() } if (!Zend_Session::isStarted()) { - if (!$useDb) { self::dropUnreadableSessionId(); } - Zend_Session::start(); + // A session id the BROWSER still carries can be one this process cannot use: cPanel's shared + // session directory after an account is deleted and recreated (the files handler's file + // belongs to the old uid; every returning visitor to the domain hits it), or any unknown id + // a client presents. Strict mode is the standard defence — PHP rejects an uninitialised id + // and mints a fresh one itself, so nothing reads the foreign file and no phantom id survives + // to trip a later regenerate. cPanel leaves it off; turn it on. (Belt: drop a provably + // unreadable files id too, for a SAPI where strict mode is disabled outright.) + @ini_set('session.use_strict_mode', '1'); + self::dropUnreadableSessionId(); + try { + Zend_Session::start(); + } catch (Zend_Session_Exception $e) { + // Last resort: forget the presented id entirely and start clean, so a visitor is a guest, + // never a 500. (Regenerate needs an active session, so clear the cookie + reset the id.) + error_log('Tiger session: start failed (' . $e->getMessage() . '); starting a clean session'); + if (!headers_sent()) { @setcookie(session_name(), '', ['expires' => 1, 'path' => '/']); } + unset($_COOKIE[session_name()]); + if (session_status() !== PHP_SESSION_ACTIVE) { session_id(bin2hex(random_bytes(16))); Zend_Session::start(); } + } } } diff --git a/library/Tiger/Version.php b/library/Tiger/Version.php index 6b0e24d..ab50b3e 100644 --- a/library/Tiger/Version.php +++ b/library/Tiger/Version.php @@ -9,5 +9,5 @@ class Tiger_Version { /** Current Tiger Core version. Keep in lockstep with the git tag cut for a release. */ - const VERSION = '1.8.2'; + const VERSION = '1.8.3'; }