Bug report: a regular user setting a flair that contained a reserved staff word (admin, sysop, moderator, root, etc.) got a blank 500 page instead of the intended "that's not allowed" flash.
Root cause was a stale magic number inside ForumController::reportFlairViolation(): $securityForumId = 206. That id doesn't exist in the current DB — the Security Issues forum is actually id 2124 today, because the forum tree has been reseeded / renumbered since the flair-violation reporter was written. ForumThread::create() hit the forum_threads_ibfk_1 FK constraint and threw an uncaught PDOException, which the error handler surfaced as a 500.
What changed:
- Forum lookup by slug.
reportFlairViolation()now callsForum::findBySlug('security-issues')instead of carrying a hardcoded id, so a future renumber or reseed can't break this path again. If the forum is genuinely missing, a warning is logged and the reporter bails cleanly. - Caller-side try/catch. The whole
reportFlairViolation()call is wrapped so ANY remaining failure in the admin-notification path (DB hiccup, markdown service down, etc.) degrades to a logged warning instead of a 500 in the middle of a user's flair-save flow. The audit-log entry written before the reporter runs still captures the attempt — the security trail survives regardless. - Clearer error copy. Flash now reads: "That flair text is not allowed — staff role names ('admin', 'sysop', 'moderator', 'root', 'staff', 'owner' and similar) are reserved to prevent impersonation. Pick something else." Answers the why without the user having to guess which pattern matched.
Detection logic is unchanged — same blocked-pattern list guards variations (sys op, super admin, mod, superuser, etc.). Every attempt still lands as its own thread in /forums/security-issues for admin review, which is the design.
. __ ____ ___ ____ _ _
/ /_| ___| / _ \___ \(_)___| |__
| '_ \___ \| | | |__) | / __| '_ \
| (_) |__) | |_| / __/| \__ \ | | |
\___/____/ \___/_____|_|___/_| |_|
D2sk - Sysop