Read receipts stored as explicit user acknowledgment, not inferred from delivery
Why it matters
Inferring read status from message delivery lies to users about what their conversation partners have actually seen. A message marked read the instant it lands on a device claims acknowledgment the recipient never gave, which breaks trust in the product, corrupts engagement analytics built on receipt events, and creates evidentiary problems in regulated workflows (harassment reports, support SLAs, legal discovery) where read receipts are treated as proof the user saw the content. Data-integrity failures here cascade: downstream features like unread counts, notification suppression, and retention funnels all key off a signal that does not represent reality.
Severity rationale
Medium because the integrity breach misleads users and distorts analytics but does not by itself expose credentials or enable account takeover.
Remediation
Require a deliberate client action before recording a read receipt and persist the receipt only in response to that action. Wire a mark_as_read socket event that fires when the message enters the viewport or the user focuses the conversation, then write the receipt in your realtime handler (for example src/server/socket/handlers/read-receipts.ts) and fan out to other participants.
socket.on('mark_as_read', async ({ messageId, channel }) => {
await db.readReceipts.create({ messageId, userId: socket.userId, channel, timestamp: new Date() });
io.to(channel).emit('read_receipt', { messageId, userId: socket.userId, timestamp: new Date() });
});
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Real-Time Communication Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
Taxons
History
- 2026-04-18·v1.0.0·Initial import from community-realtime·automated