security: validate <delay> from and <stanza-id> by attributes
Some checks failed
CI Code / Check spelling (pull_request) Successful in 17s
CI Code / Check coding style (pull_request) Successful in 32s
CI Code / Code Coverage (pull_request) Failing after 10m1s
CI Code / Linux (debian) (pull_request) Failing after 12m32s
CI Code / Linux (ubuntu) (pull_request) Failing after 12m45s
CI Code / Linux (arch) (pull_request) Failing after 13m30s

XEP-0203 §4 (Delayed Delivery):
Remote clients could inject <delay xmlns='urn:xmpp:delay'> elements
with arbitrary timestamps, causing messages to appear at incorrect
positions in chat history.  The spec mandates checking the 'from'
attribute to verify the delay was added by a trusted source.

- stanza.c: add stanza_get_oldest_delay_from(stanza, from) that
  filters <delay>/<x> children by the 'from' attribute; refactor
  stanza_get_oldest_delay() to delegate with from=NULL.  Add
  NULL-safety for tmp timestamp in comparison logic.
- stanza.h: declare stanza_get_oldest_delay_from().
- message.c (_handle_chat): replace unfiltered stanza_get_delay()
  with trust-ordered fallback: our domain → sender domain → now.
- message.c (_handle_groupchat): replace stanza_get_oldest_delay()
  with fallback: room bare JID → room domain → our domain → now.
- message.c (_handle_muc_private_message): same pattern.

MAM path deliberately unchanged — <delay> inside <forwarded> is
already from our own server's archive.

XEP-0359 §5 (Unique and Stable Stanza IDs):
The <stanza-id> element was accepted without checking the 'by'
attribute, allowing a remote client to inject forged archive IDs.

- stanza.h: add STANZA_ATTR_BY define.
- message.c (_handle_groupchat): only accept <stanza-id> when
  by == room bare JID.
- message.c (_handle_chat): only accept <stanza-id> when
  by == our server domain.
This commit is contained in:
2026-02-21 18:24:53 +03:00
committed by jabber.developer2
parent 06b80bc89a
commit 7fb926c78a
3 changed files with 64 additions and 20 deletions

View File

@@ -196,6 +196,7 @@
#define STANZA_ATTR_FILENAME "filename"
#define STANZA_ATTR_SIZE "size"
#define STANZA_ATTR_CONTENTTYPE "content-type"
#define STANZA_ATTR_BY "by"
#define STANZA_ATTR_LABEL "label"
#define STANZA_TEXT_AWAY "away"
@@ -331,6 +332,7 @@ gboolean stanza_contains_chat_state(xmpp_stanza_t* stanza);
GDateTime* stanza_get_delay(xmpp_stanza_t* const stanza);
GDateTime* stanza_get_delay_from(xmpp_stanza_t* const stanza, gchar* from);
GDateTime* stanza_get_oldest_delay(xmpp_stanza_t* const stanza);
GDateTime* stanza_get_oldest_delay_from(xmpp_stanza_t* const stanza, const char* const from);
gboolean stanza_is_muc_presence(xmpp_stanza_t* const stanza);
gboolean stanza_is_muc_self_presence(xmpp_stanza_t* const stanza,