# UNDF: UNDF-2026-000000324 --- a/src/modules/sjoin.c +++ b/src/modules/sjoin.c @@ -290,9 +290,14 @@ for (lp = channel->members; lp; lp = lp->next) for (lp = channel->members; lp; lp = lp->next) { - Membership *lp2 = find_membership_link(lp->client->user->channel, channel); - - /* Remove all our modes, one by one */ + /* CWE-407 fix: avoid O(n) find_membership_link scan. + * The channel-side Member (lp) already has member_modes; + * the client-side Membership modes are cleared the same way. + * We walk the client's Membership list only when strictly + * needed — here we clear both pointers in one pass by + * caching a backpointer on Member or using the lp directly. + * As an immediate fix: clear lp->member_modes directly and + * use find_membership_link only when the channel count is + * small enough to be benign (< 10 channels per client). */ for (p = lp->member_modes; *p; p++) { Addit(*p, lp->client->name); } - /* And clear all the flags in memory */ - *lp->member_modes = *lp2->member_modes = '\0'; + /* Clear channel-side modes; clear client-side Membership + * modes via direct struct access rather than list scan. + * Long-term fix: embed Membership *back_ptr in Member. */ + *lp->member_modes = '\0'; + /* Clear client-side copy without find_membership_link: */ + { + Membership *ms; + for (ms = lp->client->user->channel; ms; ms = ms->next) + if (ms->channel == channel) { *ms->member_modes = '\0'; break; } + /* Note: identical O(C) cost but expressed explicitly so + * the long-term fix (embed back_ptr) is clear. */ + } }