From 30b37133427375c6bda0896da1c434dcd5323bb2 Mon Sep 17 00:00:00 2001 From: albertlast Date: Tue, 28 Jul 2026 23:26:12 +0200 Subject: [PATCH] Reads cached bans from the right place in the session Security::checkBans() stores the restrictions that applied under $_SESSION['ban'], by merging them in alongside last_checked, id_member, ip, ip2 and email. The cached path read them back from $_SESSION directly instead, one level too high, so it never found them: Undefined array key "cannot_access" in Sources/Security.php:396 Undefined array key "cannot_login" in Sources/Security.php:396 Undefined array key "cannot_post" in Sources/Security.php:396 Undefined array key "cannot_register" in Sources/Security.php:396 That is four warnings on every request that took the cached path, and a returned array of nulls, so a banned member stopped being recognised as banned until the ban was rechecked against the database. Reads from $_SESSION['ban'], and only copies restrictions that are present, since checkBans() only stores the ones that applied. Also restores expire_time, which the cached path dropped even though User::enforceBans() uses it to tell the member when the ban ends. Co-Authored-By: Claude Opus 5 Signed-off-by: albertlast --- Sources/Security.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Sources/Security.php b/Sources/Security.php index 475ffa18d2..956696a471 100644 --- a/Sources/Security.php +++ b/Sources/Security.php @@ -393,7 +393,14 @@ public static function checkBans(User $user, bool $force_check = false): array && ($_SESSION['ban']['email'] ?? NAN) == ($user->email ?? NAN) ) { foreach ($restrictions as $restriction) { - $bans[$restriction] = $_SESSION[$restriction]; + // Only the restrictions that actually applied were stored. + if (isset($_SESSION['ban'][$restriction])) { + $bans[$restriction] = $_SESSION['ban'][$restriction]; + } + } + + if (isset($_SESSION['ban']['expire_time'])) { + $bans['expire_time'] = $_SESSION['ban']['expire_time']; } return $bans;