etherpad-lite/doc/privacy.md
John McLear 6195289198
feat(gdpr): IP/privacy audit (PR2 of #6701) (#7547)
* docs: PR2 GDPR IP/privacy audit design spec

Second of five GDPR PRs (#6701). Audit identifies four log-sites that
leak IPs despite disableIPlogging=true, proposes a tri-state ipLogging
setting with a back-compat shim, and specifies a doc/privacy.md that
documents Etherpad's actual IP handling.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: PR2 GDPR IP/privacy audit implementation plan

7 TDD-structured tasks: anonymizeIp helper + unit tests, tri-state
ipLogging setting with disableIPlogging deprecation shim, wiring
through 5 leaking log sites, clientVars.clientIp removal, access-log
integration test, doc/privacy.md, and PR handoff.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(gdpr): anonymizeIp helper with v4/v6/v4-mapped truncation

* feat(gdpr): tri-state ipLogging setting + disableIPlogging shim

* fix(gdpr): route every IP log site through anonymizeIp

Closes four leaks where disableIPlogging was silently ignored
(rate-limit warn, both auth-log calls in webaccess, import/export
rate-limit warn) and normalises the four that did honour the flag
onto the new ipLogging tri-state via the shared helper.

* chore(gdpr): drop dead clientVars.clientIp placeholder

Server side: remove the literal '127.0.0.1' assignments from both
clientVars and collab_client_vars. Type side: drop clientIp from
ClientVarPayload and ServerVar. pad.getClientIp now returns the same
'127.0.0.1' literal as a plugin-compat shim (pad_utils.uniqueId still
uses it as a prefix).

* test(gdpr): ipLogging modes + disableIPlogging shim

* docs(gdpr): operator-facing privacy and IP handling statement

* fix(gdpr): validate ipLogging at load + regression test for log sites

Qodo review:
- settings.ipLogging is loaded as a trusted union but nothing enforced
  the shape. An unknown value (e.g. a typo or null) silently fell
  through to anonymizeIp's "truncated" branch and emitted partially
  redacted IPs. Fall back to "anonymous" with a WARN at load time.
- New regression test scans the four known log-sites for raw
  req.ip / socket.request.ip / request.ip inside logger calls that
  don't wrap through anonymizeIp / logIp, so a future edit that
  re-introduces a raw IP fails CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 13:47:40 +01:00

2.5 KiB

Privacy

This document describes what Etherpad stores and logs about its users, so operators can publish an accurate data-processing statement.

Pad content and author identity

  • Pad text, revision history, and chat messages are written to the configured database (see dbType / dbSettings).
  • Authorship is tracked by an opaque authorID that is bound to a short-lived author-token cookie. There is no link between an authorID and a real-world identity unless a plugin or SSO layer adds one.

IP addresses

Etherpad never writes a client IP to its database. IPs only appear in log4js output (the access, http, message, and console loggers). Whether those are persisted depends entirely on the log appender your deployment configures.

The ipLogging setting (settings.json) controls what those log records contain. All five log sites respect it:

Setting value Access / auth / rate-limit log contents
"anonymous" (default) the literal string ANONYMOUS
"truncated" IPv4 with last octet zeroed (1.2.3.0); IPv6 truncated to the first /48 (2001:db8:1::); IPv4-mapped IPv6 truncates the embedded v4; unknowns fall back to ANONYMOUS
"full" the original IP address

The pre-2026 boolean disableIPlogging is still honoured for one release cycle: true maps to "anonymous", false maps to "full". A deprecation WARN is emitted when only the legacy setting is present.

Rate limiting

The in-memory socket rate limiter keys on the raw client IP for the duration of the limiter window (see commitRateLimiting in settings.json). This state is never written to disk, never sent to a plugin, and is thrown away on server restart.

What Etherpad does not do

  • No IP addresses are written to the database.
  • No IP addresses are sent to clientVars (and therefore to the browser). The long-standing clientIp: '127.0.0.1' placeholder was removed in the same change that introduced ipLogging.
  • No IP addresses are passed to server-side plugin hooks by Etherpad itself. Plugins that receive a raw req can still read req.ip directly — audit your installed plugins if you need to rule that out.

Cookies

See cookies.md for the full cookie list.

Right to erasure

See ../docs/superpowers/specs/2026-04-18-gdpr-pr1-deletion-controls-design.md for the deletion-token mechanism. Full author erasure is tracked as a follow-up in ether/etherpad#6701.