Without monotonic sequence numbers, clients have no way to detect that messages were dropped during a network disruption. A user rejoining after a brief outage will see the conversation with silent gaps — no indication that messages are missing. CWE-354 (Improper Validation of Integrity Check Value) covers this class of missing-integrity-signal failure. In a community app, undetected gaps corrupt conversation context, cause replies to appear to reference messages that were never received, and erode user trust in the platform's reliability.
High because clients cannot detect dropped messages during network outages, silently corrupting conversation state and breaking reply threading.
Attach a per-channel monotonic sequence counter to every outgoing message at the server. Clients compare consecutive sequence numbers to detect gaps and trigger a catch-up request.
const channelSeq = new Map<string, number>();
socket.on('send_message', (data: { channel: string; content: string }) => {
const seq = (channelSeq.get(data.channel) ?? 0) + 1;
channelSeq.set(data.channel, seq);
const message = {
id: nanoid(),
seq,
channel: data.channel,
content: data.content,
userId: socket.userId,
timestamp: Date.now(),
};
io.to(data.channel).emit('message', message);
});
For multi-instance deployments, store the counter in Redis (INCR channel:{id}:seq) rather than in process memory so the sequence is consistent across pods.
ID: community-realtime.message-delivery.monotonic-sequence-numbers
Severity: high
What to look for: Enumerate all message sending paths. For each, check for a sequence number or version counter attached to each message. Count the paths that include monotonic sequence numbers.
Pass criteria: 100% of message sending paths include a sequence number that increments monotonically (1, 2, 3, ...) per channel. Clients can detect missed messages by comparing consecutive sequence numbers. Gaps of at least 1 indicate missed messages.
Fail criteria: Messages lack sequence numbers, or sequence numbers are not monotonic.
Skip (N/A) when: Never — sequence numbers are essential for detecting message loss.
Detail on fail: "Messages sent without sequence numbers. Clients cannot detect if messages were lost during network outages."
Remediation: Attach monotonic sequence numbers to messages at the server:
interface Message {
id: string;
seq: number; // Monotonic per channel
content: string;
userId: string;
timestamp: number;
}
let channelSeq = new Map<string, number>();
socket.on('send_message', (data: { channel: string; content: string }) => {
const seq = (channelSeq.get(data.channel) ?? 0) + 1;
channelSeq.set(data.channel, seq);
const message: Message = {
id: nanoid(),
seq,
content: data.content,
userId: socket.userId,
timestamp: Date.now(),
};
io.to(data.channel).emit('message', message);
});