[Critique] Les messages de DM sont diffusés en temps réel (SignalR NewMessage) à tous les utilisateurs connectés #83

Closed
opened 2026-10-28 10:31:48 +00:00 by asventi · 0 comments
Owner

Gravité : Critique
Rapports QA d'origine : FRIENDS-01b, SECURITY_UX-06

Le hub envoie NewMessage à tous les users en ligne au lieu des seuls membres du channel : un tiers reçoit le contenu des DM en clair.

Détails des rapports

[FRIENDS-01b] Les messages de DM sont diffusés en temps réel (SignalR) à TOUS les utilisateurs connectés — Gravité : Critique
  • Où : hub SignalR /api/ événement NewMessage (aussi UpdateMessage, RemoveMessage)
  • Étapes : 1. C se connecte via l'UI (/messages) et on écoute les frames WebSocket de sa page. 2. A envoie "LEAKCHECK-live-message" dans le DM A<->B (API).
  • Attendu : seuls A et B reçoivent l'événement.
  • Obtenu : la page de C reçoit la frame {"type":1,"target":"NewMessage","arguments":["<convId>",{... "content":"LEAKCHECK-live-message" ...,"sender":{...,"email":...}}]}.
  • Preuve : sortie de scripts/friends/leak.py ("frames: 5 leaked: 1"), screenshot screens/friends_01_C_home_messages.png.
  • Cause probable : backend/API/Channels/Messages/Create/CreateMessageCommand.cs (et Update/Delete) : hub.Clients.Users(onlineUsers.Where(channel.IsWhitelisted)) => tous les users en ligne pour un DM. Devrait cibler channel.Members.
[SECURITY_UX-06] Fuite temps réel SignalR : le contenu des DM est diffusé à tous les utilisateurs en ligne — Gravité : Critique
  • Où : hub SignalR (/api/negotiate + WebSocket /api/?id=...), évènement NewMessage (idem UpdateMessage, RemoveMessage par lecture du code)
  • Étapes : 1. C (Member, tiers) se connecte au hub (négociation avec ses cookies, WebSocket, handshake JSON). 2. A poste un message dans sa conversation privée avec B (POST /channels/{conv}/messages).
  • Attendu : seuls A et B reçoivent l'évènement.
  • Obtenu : C reçoit {"type":1,"target":"NewMessage","arguments":["<id du DM A-B>",{"content":"qa_sec SIGNALR-LEAK-...","sender":{... "email":"qa_security_ux_a_...@qa.test" ...}}]} en clair.
  • Preuve : scripts/security_ux/signalr.py (sortie « C recoit: ... NewMessage ... »). Sans cookie, POST /api/negotiate -> 401 (OK).
  • Cause probable : backend/API/Channels/Messages/Create/CreateMessageCommand.cs (destinataires = users en ligne filtrés par channel.IsWhitelisted, vrai pour tous sur un DM, cf. SECURITY_UX-01). Les ids des DM fuitent ainsi vers tous les users, ce qui rend SECURITY_UX-01 directement exploitable.

Trouvé par une campagne de tests QA automatisés (agents Claude, Playwright) sur l'environnement de dev. Les captures citées sont locales et non jointes.

**Gravité :** Critique **Rapports QA d'origine :** FRIENDS-01b, SECURITY_UX-06 Le hub envoie `NewMessage` à tous les users en ligne au lieu des seuls membres du channel : un tiers reçoit le contenu des DM en clair. ## Détails des rapports <details><summary>[FRIENDS-01b] Les messages de DM sont diffusés en temps réel (SignalR) à TOUS les utilisateurs connectés — Gravité : Critique</summary> - Où : hub SignalR `/api/` événement `NewMessage` (aussi `UpdateMessage`, `RemoveMessage`) - Étapes : 1. C se connecte via l'UI (/messages) et on écoute les frames WebSocket de sa page. 2. A envoie "LEAKCHECK-live-message" dans le DM A<->B (API). - Attendu : seuls A et B reçoivent l'événement. - Obtenu : la page de C reçoit la frame `{"type":1,"target":"NewMessage","arguments":["<convId>",{... "content":"LEAKCHECK-live-message" ...,"sender":{...,"email":...}}]}`. - Preuve : sortie de `scripts/friends/leak.py` ("frames: 5 leaked: 1"), screenshot `screens/friends_01_C_home_messages.png`. - Cause probable : `backend/API/Channels/Messages/Create/CreateMessageCommand.cs` (et Update/Delete) : `hub.Clients.Users(onlineUsers.Where(channel.IsWhitelisted))` => tous les users en ligne pour un DM. Devrait cibler `channel.Members`. </details> <details><summary>[SECURITY_UX-06] Fuite temps réel SignalR : le contenu des DM est diffusé à tous les utilisateurs en ligne — Gravité : Critique</summary> - Où : hub SignalR (`/api/negotiate` + WebSocket `/api/?id=...`), évènement `NewMessage` (idem `UpdateMessage`, `RemoveMessage` par lecture du code) - Étapes : 1. C (Member, tiers) se connecte au hub (négociation avec ses cookies, WebSocket, handshake JSON). 2. A poste un message dans sa conversation privée avec B (`POST /channels/{conv}/messages`). - Attendu : seuls A et B reçoivent l'évènement. - Obtenu : C reçoit `{"type":1,"target":"NewMessage","arguments":["<id du DM A-B>",{"content":"qa_sec SIGNALR-LEAK-...","sender":{... "email":"qa_security_ux_a_...@qa.test" ...}}]}` en clair. - Preuve : `scripts/security_ux/signalr.py` (sortie « C recoit: ... NewMessage ... »). Sans cookie, `POST /api/negotiate` -> 401 (OK). - Cause probable : `backend/API/Channels/Messages/Create/CreateMessageCommand.cs` (destinataires = users en ligne filtrés par `channel.IsWhitelisted`, vrai pour tous sur un DM, cf. SECURITY_UX-01). Les ids des DM fuitent ainsi vers tous les users, ce qui rend SECURITY_UX-01 directement exploitable. </details> --- _Trouvé par une campagne de tests QA automatisés (agents Claude, Playwright) sur l'environnement de dev. Les captures citées sont locales et non jointes._
Equoo self-assigned this 2026-10-28 11:02:09 +00:00
Equoo referenced this issue from a commit 2026-10-29 01:06:33 +00:00
Equoo closed this issue 2026-10-29 01:06:49 +00:00
Equoo referenced this issue from a commit 2026-10-29 13:05:36 +00:00
Equoo referenced this issue from a commit 2026-10-31 19:16:18 +00:00
asventi referenced this issue from a commit 2026-11-02 13:08:20 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transcendence/backend#83
No description provided.