From 0d6b08f5d288e61e2007a69636075fa34da2ec1f Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Tue, 8 Sep 2026 11:53:36 -0400 Subject: [PATCH] Cap get_users.php result set as defense-in-depth (#42) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit api/get_users.php returned every user's user_id/username/display_name to any authenticated session with no pagination or limit — needed for mention/assignment typeahead, but a blanket enumeration a compromised low-privilege session could scrape in one call. Added a LIMIT 500; every caller already only uses this for typeahead/dropdown filtering, never a literal full roster, so this doesn't change behavior for any real deployment size while bounding the response. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01MGDKHiU5RJdo3dqQUDow3X --- api/get_users.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/api/get_users.php b/api/get_users.php index 77e0afd..5971ee3 100644 --- a/api/get_users.php +++ b/api/get_users.php @@ -8,8 +8,10 @@ require_once __DIR__ . '/bootstrap.php'; try { - // Get all users for mentions/assignment - $result = Database::query("SELECT user_id, username, display_name FROM users ORDER BY display_name, username"); + // Get all users for mentions/assignment. Capped as defense-in-depth against + // a single call scraping an unbounded user list — every caller only needs + // this for typeahead/dropdown filtering, never a literal full roster. + $result = Database::query("SELECT user_id, username, display_name FROM users ORDER BY display_name, username LIMIT 500"); if (!$result) { throw new Exception("Failed to query users");