etherpad-lite/doc/cookies.md
John McLear 21e1ae2fa3
security: allow integrator sessionID cookie to be HttpOnly (#7045) (#7755)
* security: allow integrator sessionID cookie to be HttpOnly (#7045)

The integrator-set sessionID cookie was forced to be non-HttpOnly because
Etherpad's own client JS read it via document.cookie and forwarded it in
the socket.io CLIENT_READY payload, exposing it to XSS.

Mirror the GDPR PR3 author-token migration: read sessionID from the
socket.io handshake's Cookie header in PadMessageHandler.handleClientReady,
falling back to the legacy message-level field with a one-time deprecation
warning per socket. Drop the client-side Cookies.get('sessionID') reads in
pad.ts and timeslider.ts so the field is no longer sent by current clients.

Existing integrators that set sessionID without HttpOnly keep working
unchanged; the field on the message becomes optional and integrators
should now mark the cookie HttpOnly; Secure; SameSite=Lax.

Closes #7045

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

* fix(security): treat undecodable handshake cookies as absent (Qodo #7755)

decodeURIComponent() throws URIError on malformed values like `%ZZ`. The
unguarded call in PadMessageHandler.handleClientReady's readCookie() let
a single bad cookie abort CLIENT_READY for that socket, allowing
unauthenticated peers to spam server error logs and lock themselves out
of pads.

Catch URIError and treat the value as absent so the legacy message-level
field still serves as a fallback. Other error classes still propagate.
Add a backend test that asserts a `sessionID=%ZZ` cookie no longer
aborts the handshake.

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-15 19:44:55 +01:00

6.7 KiB

Cookies

Cookies used by Etherpad.

Name Sample value Domain Path Expires/max-age Http-only Secure Usage description
express_sid s%3A7yCNjRmTW8ylGQ53I2IhOwYF9... example.org / Session true true Session ID of the Express web framework. When Etherpad is behind a reverse proxy, and an administrator wants to use session stickiness, he may use this cookie. If you are behind a reverse proxy, please remember to set trustProxy: true in settings.json. Set in webaccess.js#L131.
language en example.org / Session false true The language of the UI (e.g.: en-GB, it). Set by the pad client when the user changes My View → Language (currently in src/static/js/pad.ts, via setMyViewLanguage()).
prefs / prefsHttp %7B%22epThemesExtTheme%22... example.org /p year 3000 false true Client-side preferences (e.g.: font family, chat always visible, show authorship colors, ...). Set in pad_cookie.js#L49. prefs is used if Etherpad is accessed over HTTPS, prefsHttp if accessed over HTTP. For more info see https://github.com/ether/etherpad-lite/issues/3179.
token t.tFzkihhhBf4xKEpCK3PU example.org / 60 days true true A random token representing the author, of the form t.randomstring_of_length_20. Set by the server as an HttpOnly; SameSite=Lax cookie on the first GET to /p/:pad (see src/node/utils/ensureAuthorTokenCookie.ts). The server reads the cookie from the socket.io handshake in PadMessageHandler.handleClientReady to resolve the author. Not readable from browser JavaScript. See privacy.md.

For more info, visit the related discussion at https://github.com/ether/etherpad-lite/issues/3563.

Etherpad HTTP API clients may make use (if they choose so) to send another cookie:

Name Sample value Domain Usage description
sessionID s.1c70968b333b25476a2c7bdd0e0bed17 example.org Sessions can be created between a group and an author. This allows an author to access more than one group. The sessionID is set as a cookie by the integrator and is valid until a certain date. The session cookie can also contain multiple comma-separated sessionIDs, allowing a user to edit pads in different groups at the same time. Since #7045 Etherpad reads this cookie server-side from the socket.io handshake, so integrators should set it as HttpOnly; Secure; SameSite=Lax to mitigate XSS. More info - https://github.com/ether/etherpad-lite/blob/develop/doc/api/http_api.md#session