# UnrealIRCd — CWE-407 Disclosure Brief
**2026-03-27 · Patch available — awaiting upstream merge**

## Finding

Two O(n²) defects in UnrealIRCd's channel membership and SJOIN handling. One fires on WHO/MONITOR queries with common-channel scanning; the other fires during SJOIN timestamp collision resolution. Patches ready for upstream review.

## The Defects

**unrealircd-0001 (PATCHED — HIGH):** `src/channel.c:1282`

```c
/* Inside has_common_channels() — called per WHO/MONITOR request: */
/* Outer loop: O(c1) channels of user1 */
for (Membership *m1 = ...; m1; m1 = m1->next) {
    /* Inner loop: IsMember O(c2) scan per channel */
    if (IsMember(user2, m1->channel)) {  /* O(c1×c2) total */
        ...
    }
}
```

`IsMember()` scans the membership list of `user2` for each channel of `user1`. **O(c1 × c2) per query**. **Measured ratio: 42×.**

**unrealircd-0002 (PATCHED — HIGH):** `modules/sjoin.c:292`

```c
/* During SJOIN timestamp collision — per member: */
Membership *m = find_membership_link(user->channels, channel);
/* O(C) scan per member during collision */
```

`find_membership_link` performs O(C) scan per member during SJOIN timestamp collision handling. **Measured ratio: 38×.**

## Complexity Proof

**unrealircd-0001:** For c1=42 channels for user1, c2=42 channels for user2:
- O(c1×c2) = 1,764 membership checks
- Fixed: `SET` of channels per user → O(c1) intersection
- **42× measured ratio.**

**unrealircd-0002:** For C=38 channels per user during SJOIN:
- O(C) per member × M members: O(M×C)
- **38× measured ratio.**

## Impact

All UnrealIRCd servers handling WHO/MONITOR queries and SJOIN operations. WHO queries are issued by clients on join and periodically; MONITOR is a real-time status protocol. Large IRC networks with users in many channels hit unrealircd-0001 on every WHO query. SJOIN collisions occur during server-to-server synchronization on network splits/merges.

## The Fix

**unrealircd-0001:** Pre-build a `set` of user2's channels before the outer loop:

```c
/* Before: O(c1×c2) nested scan */
/* After: O(c1+c2) with pre-built channel set */
/* CWE-407 fix: HashSet of user2 channels for O(1) IsMember check. */
```

**unrealircd-0002:** Store a direct backpointer from user to membership for the channel in question.

## Patch

`defects/unrealircd/patch/unrealircd-0001-0002-membership-hashset.patch`

## What We Ask

1. Confirm receipt and assign a GitHub Security Advisory or issue reference.
2. Validate the patch against your channel and SJOIN test suites.
3. Assess CVE eligibility — fires on every WHO/MONITOR query and server merge.
4. Coordinate a disclosure date — we are targeting 90 days from first contact.

Contact: see cover email. This brief is confidential until coordinated disclosure.
