XMPP: chat-_pending onbegrensd + head-of-line blocking — geheugen-DoS en chat-blokkade #1412

Closed
opened 2026-08-09 18:22:59 +00:00 by brenno · 0 comments
Owner

Bevinding

lib/xmpp/xmpp_chat.dart — de _pending-lijst (regel 110) is een List<SealedEnvelope> zonder cap. retryPending (regels 188–202) verwerkt de lijst van voren en breekt bij het eerste bericht dat niet geopend kan worden (_open retourneert null bij een onbekende afzender).

Twee problemen

1. Head-of-line blocking. Eén stanza met een onbekend senderDevice blokkeert de hele buffer. directory.resolve(sealed.senderDevice) retourneert null, _open retourneert null, retryPending breekt — alle volgende berichten (ook van bekende afzenders) blijven in _pending staan en worden nooit getoond. Een enkele vijandige stanza met een verzonnen senderDevice schakelt de hele chat uit.

2. Onbegrensde groei. Elke inbound <chat>-stanza wordt aan _pending toegevoegd (regel 179) vóór retryPending. Als de head-of-line blokkeert, groeit _pending onbegrensd met elke nieuwe stanza — geheugen-exhaustie. Een vijandige server (of MUC die groupchat reflecteert) kan dit uitbuiten door een stroom berichten te sturen.

Trust boundary

MUC (companion room) → Applicatie (chat-buffer). De MUC reflecteert elke groupchat-message; een occupant kan stanzas sturen met een willekeurig senderDevice in de verzegeling.

Impact

  • Chat wordt onbruikbaar door één vijandige stanza (head-of-line blocking).
  • Geheugen-exhaustie door aanhoudende stroom (onbegrensde _pending).
  • Geen foutmelding aan de gebruiker — de chat toont gewoon niets meer.

Oplossingsrichting

  1. Begrens _pending met een cap (bijv. 256, vergelijkbaar met _maxDeferred in het transport). Bij overflow verdrijf het oudste (FIFO).
  2. Sla onbekende afzenders niet permanent over — verwerk de lijst verder in plaats van te breken bij het eerste onopenbare bericht. Een bericht met een onbekende afzender blijft staan, maar volgende berichten van bekende afzenders worden wel getoond. Dit betekent dat retryPending niet break-t bij null maar continue-t.
  3. Aanvullend: overweeg een time-out op _pending-entries — een bericht dat na N ronden nog niet openbaar is, wordt fail-closed gedropt (vergelijkbaar met _maxDeferralRounds in het transport).

Locatie

  • lib/xmpp/xmpp_chat.dart regels 106–114 (_pending-declaratie), 161–184 (handleChat), 188–202 (retryPending), 209–234 (_open)

Severity

MEDIUM — chat is niet-veiligheidskritiek, maar de blokkade is onzichtbaar en de geheugen-DoS is reëel.

## Bevinding `lib/xmpp/xmpp_chat.dart` — de `_pending`-lijst (regel 110) is een `List<SealedEnvelope>` zonder cap. `retryPending` (regels 188–202) verwerkt de lijst van voren en **breekt** bij het eerste bericht dat niet geopend kan worden (`_open` retourneert `null` bij een onbekende afzender). ### Twee problemen **1. Head-of-line blocking.** Eén stanza met een onbekend `senderDevice` blokkeert de hele buffer. `directory.resolve(sealed.senderDevice)` retourneert `null`, `_open` retourneert `null`, `retryPending` breekt — alle volgende berichten (ook van bekende afzenders) blijven in `_pending` staan en worden nooit getoond. Een enkele vijandige stanza met een verzonnen `senderDevice` schakelt de hele chat uit. **2. Onbegrensde groei.** Elke inbound `<chat>`-stanza wordt aan `_pending` toegevoegd (regel 179) vóór `retryPending`. Als de head-of-line blokkeert, groeit `_pending` onbegrensd met elke nieuwe stanza — geheugen-exhaustie. Een vijandige server (of MUC die groupchat reflecteert) kan dit uitbuiten door een stroom berichten te sturen. ### Trust boundary MUC (companion room) → Applicatie (chat-buffer). De MUC reflecteert elke groupchat-message; een occupant kan stanzas sturen met een willekeurig `senderDevice` in de verzegeling. ### Impact - Chat wordt onbruikbaar door één vijandige stanza (head-of-line blocking). - Geheugen-exhaustie door aanhoudende stroom (onbegrensde `_pending`). - Geen foutmelding aan de gebruiker — de chat toont gewoon niets meer. ### Oplossingsrichting 1. **Begrens `_pending`** met een cap (bijv. 256, vergelijkbaar met `_maxDeferred` in het transport). Bij overflow verdrijf het oudste (FIFO). 2. **Sla onbekende afzenders niet permanent over** — verwerk de lijst verder in plaats van te breken bij het eerste onopenbare bericht. Een bericht met een onbekende afzender blijft staan, maar volgende berichten van bekende afzenders worden wel getoond. Dit betekent dat `retryPending` niet `break`-t bij `null` maar `continue`-t. 3. **Aanvullend:** overweeg een time-out op `_pending`-entries — een bericht dat na N ronden nog niet openbaar is, wordt fail-closed gedropt (vergelijkbaar met `_maxDeferralRounds` in het transport). ### Locatie - `lib/xmpp/xmpp_chat.dart` regels 106–114 (`_pending`-declaratie), 161–184 (`handleChat`), 188–202 (`retryPending`), 209–234 (`_open`) ### Severity MEDIUM — chat is niet-veiligheidskritiek, maar de blokkade is onzichtbaar en de geheugen-DoS is reëel.
brenno 2026-08-09 20:56:23 +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
LibreKAT/Ocideck#1412
No description provided.