# Presence payloads contain only state and user ID; no IP, device, or session data leaked

- **Pattern:** `ab-000748` (`community-realtime.presence.presence-data-privacy`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000748
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000748)

## Why it matters

Presence payloads broadcast to every connected client in a channel. Embedding IP addresses, user-agent strings, device names, or session tokens in those payloads exposes that data to all channel members — not just the server. This violates GDPR Article 5(1)(c) (data minimisation) and CWE-359 (Exposure of Private Personal Information to an Unauthorized Actor). A chat participant should not be able to infer another user's device, IP range, or session identifier simply by opening the developer console.

## Severity rationale

Medium because presence payloads are broadcast to all channel members, and embedding IP or device fields exposes PII to every connected peer in violation of GDPR Art. 5(1)(c).

## Remediation

Construct presence update payloads explicitly, including only `userId`, `status`, and optionally `lastActivity`. Never spread the socket handshake object into the payload.

```ts
// WRONG — leaks IP and device fingerprint to all peers
io.emit('presence_update', {
  userId: socket.userId,
  ip: socket.handshake.address,
  device: socket.handshake.headers['user-agent'],
  sessionId: socket.handshake.sessionID,
});

// CORRECT — safe minimal payload
io.emit('presence_update', {
  userId: socket.userId,
  status: 'online',
  lastActivity: Date.now(),
});
```

Review every field before adding it to a broadcast payload — if it isn't required for the recipient to render presence, exclude it.

## Detection

- **ID:** `presence-data-privacy`
- **Severity:** `medium`
- **What to look for:** List all fields in presence update payloads. For each field, classify whether it is safe (user ID, status, timestamp) or sensitive (IP, device, session, location). Count the sensitive fields found.
- **Pass criteria:** Presence payloads contain no more than 3 fields total: user ID, online status, and optionally last activity time. No IP, device, session, or location data is included.
- **Fail criteria:** Presence includes sensitive identifiers like IP addresses, session tokens, device fingerprints, or device names.
- **Skip (N/A) when:** Never — data privacy in presence is essential.
- **Cross-reference:** For broader data privacy patterns and PII handling, the Data Privacy Audit covers data exposure prevention across the application.
- **Detail on fail:** `"Presence payload includes user IP address and device ID. This information is broadcast to all connected clients."`
- **Remediation:** Only send safe presence data:

  ```ts
  // WRONG: Leaks IP and device info
  io.emit('presence_update', {
    userId: socket.userId,
    ip: socket.handshake.address,
    device: socket.handshake.headers['user-agent'],
  });

  // CORRECT: Safe presence data only
  io.emit('presence_update', {
    userId: socket.userId,
    status: 'online',
    lastActivity: Date.now(),
  });
  ```

## External references

- cwe CWE-359
- gdpr Art. 5(1)(c)

Taxons: privacy-consent

HTML version: https://auditbuffet.com/patterns/ab-000748
