Problem: Matrix DM classification logic had security vulnerabilities:
1. Unreachable code branch when is_direct flag was absent
2. When is_direct: true, skipped 2-member check (shared rooms misclassified as DMs)
3. **CWE-285: Improper Authorization** - trusted remote user's is_direct flag
Security Issues:
- Remote attacker could set is_direct=true on their membership to force DM classification
- Remote attacker could set is_direct=false to bypass DM-only restrictions
- Both could lead to policy bypass (DM allowlist/pairing checks)
Fix:
- hasDirectMatrixMemberFlag() returns boolean | null for local user only
- isStrictDirectMembership() only trusts local user's is_direct (selfUserId)
- Removed directViaSender lookups entirely (do not trust remote-controlled data)
- Falls back to strict 2-member check when is_direct is false/null
Key Insights:
- In Matrix, m.room.member.content.is_direct is set by each member themselves
- Only trust signals the bot controls (local user's membership state)
- 2-member check remains as safe fallback that cannot be manipulated
Closes#56599