File: crates/state/src/materialize.rs:540
Severity: robustness (availability/DoS)
Obvious? yes
apply_mutation(Reaction) does msg.reactions.entry(emoji.clone()).or_default().insert(event.author). The emoji string has no length cap (sibling of F11) AND there is no cap on the number of distinct reaction keys per message. A single member with SendMessages can issue N events, each with a distinct ~MB-long emoji string, growing state.messages[idx].reactions to N×MB. Worse, every replay (state materialise) re-clones each unique emoji as a BTreeMap key, so DAG-time storage cost is multiplied by every receiver.
Fix: introduce MAX_REACTION_EMOJI_BYTES (e.g. 32 bytes — emoji are short) and MAX_REACTIONS_PER_MESSAGE (e.g. 32) and enforce both in apply_mutation plus a byte-level cap in EventDag::insert for the per-event payload.
Filed by /general-audit @ 88498a5 (2026-05-04). master: #600.
File:
crates/state/src/materialize.rs:540Severity: robustness (availability/DoS)
Obvious? yes
apply_mutation(Reaction)doesmsg.reactions.entry(emoji.clone()).or_default().insert(event.author). The emoji string has no length cap (sibling of F11) AND there is no cap on the number of distinct reaction keys per message. A single member withSendMessagescan issue N events, each with a distinct ~MB-long emoji string, growingstate.messages[idx].reactionsto N×MB. Worse, every replay (state materialise) re-clones each unique emoji as aBTreeMapkey, so DAG-time storage cost is multiplied by every receiver.Fix: introduce
MAX_REACTION_EMOJI_BYTES(e.g. 32 bytes — emoji are short) andMAX_REACTIONS_PER_MESSAGE(e.g. 32) and enforce both inapply_mutationplus a byte-level cap inEventDag::insertfor the per-event payload.Filed by
/general-audit@88498a5(2026-05-04). master: #600.