Lint / PHP (phpcs PSR-12) (push) Successful in 25s
Lint / JS (eslint) (push) Successful in 10s
Lint / PHP requirements (version + extensions) (push) Successful in 1m7s
Lint / Notify on failure (push) Skipped
Security / PHP Security (semgrep) (push) Successful in 1m44s
Lint / Deploy (push) Successful in 3s
AuthMiddleware::authenticate() only re-read Remote-User/Remote-Groups (and thus is_admin, via UserModel::syncUserFromAuthelia) when $_SESSION['user'] didn't exist yet. Once a session existed, every subsequent request only checked the idle timer — never re-validating against current Authelia/LLDAP state. An admin's group membership revoked in LLDAP, or a logout at the Authelia proxy, left their already-open session with full access for up to SESSION_TIMEOUT (5h default), with no way to force early revocation short of clearing the server-side session store. Added PRIVILEGE_RESYNC_INTERVAL (default 5 min, matching UserModel's own cache TTL) and a resyncPrivileges() check on every already-authenticated request past that interval: re-reads the current request's forward-auth headers (enforcing the trusted-proxy check again, same as a fresh login), and either destroys the session and redirects to re-auth if the user no longer has any required group, or re-syncs is_admin/groups/display_name/email if they do. Best-effort if this particular request doesn't carry forward-auth headers at all (skips silently rather than force-logging out, retried next interval). UserModel::syncUserFromAuthelia() has its own 5-minute in-process cache keyed only by username (not by the groups being synced), so a naive re-call during a resync would have kept returning the pre-revocation cached result for up to 5 more minutes — invalidated that cache entry immediately beforehand to guarantee a real re-sync. Verified against real MariaDB across a fresh login, a same-interval request confirming no premature resync, an admin-privilege-revocation mid-session (is_admin flips to false in both session and DB, verified via a direct query), and a full group-membership revocation (session destroyed, redirected to re-auth, confirmed the request never reaches past that point). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lhz7pGMaoTfL5sdYS5XiKv