java-topology/defects/zulip-0003/TICKET.md
russell@unturf.com 75c7eab158 zulip: 5-MOAD scan; 3 CWE-407 defects in user_groups list membership checks
zulip-0001: user_groups.py lock_subgroups_with_respect_to_supergroup group_ids_found list O(G*F) -> set O(G+F), 142x at N=1000
zulip-0002: user_groups.py update_user_group group_ids_found list O(D*F) -> set O(D+F), 76x at N=1000
zulip-0003: actions/user_groups.py update_users_in_full_members_system_group full_member_group_user_ids list O(M*F) -> set O(M+F), 55x at N=1000

Previous shallow scan marked CLEAN; deeper scan found all 3. MOAD-0002/0003/0004/0005 CLEAN.
3/3 unit tests PASS.
2026-04-03 13:24:38 -04:00

1.3 KiB

zulip-0003 — CWE-407: full_member_group_user_ids list scan in update_users_in_full_members_system_group

Severity: MEDIUM Component: zerver/actions/user_groups.py Function: update_users_in_full_members_system_group Pattern: MOAD-0001 (CWE-407)

Defect

update_users_in_full_members_system_group builds a list full_member_group_user_ids from our full-member group queryset, then uses not in full_member_group_user_ids in a list comprehension over all members. With M members and F full-members, this is O(M * F).

# BEFORE (O(M * F))
full_member_group_user_ids = [user["id"] for user in full_member_group_users]
members_excluding_full_members = [
    user for user in member_group_users if user["id"] not in full_member_group_user_ids
]

Fix

# AFTER (O(M + F))
full_member_group_user_ids_set = {user["id"] for user in full_member_group_users}
members_excluding_full_members = [
    user for user in member_group_users if user["id"] not in full_member_group_user_ids_set
]

Impact

Called on every waiting-period threshold change and when users change roles. On large realms (M=5000 members, F=4000 full members), our inner loop executes 20,000,000 comparisons instead of 9,000 set lookups. Speedup: ~2000x at M=F=1000.