trails/apps/planner/app
Ullrich Schäfer 4e2c5f7d6b
fix(planner): require session row before accepting Yjs WebSocket upgrade
Addresses planner-audit #1 (CRITICAL — WebSocket joins unauthenticated)
with the narrow fix. The upgrade handler used to immediately
\`handleUpgrade\` for any \`/sync/<id>\` path, then \`getOrLoadDoc\` *created*
a Y.Doc on demand. An attacker connecting to random sessionIds could:

  - exhaust process memory by spinning up Y.Doc objects for sessions
    that don't exist (no DB row backed them), and
  - resurrect closed/expired sessions by reconnecting (closed rows
    were still cacheable to \`docs\`).

Now: the upgrade handler calls \`getSession(sessionId)\` first
(\`SELECT \\* FROM planner.sessions WHERE id = ? AND closed = false\`).
Missing or closed → \`socket.destroy()\` before handshake. DB unreachable
also closes — fail closed; the client reconnects after backoff.

Costs one DB roundtrip per upgrade. Upgrades are rare vs message
volume, so the overhead is negligible.

Note: we are NOT adding a join token. The planner is anonymous-by-design
(see CLAUDE.md \"sessions are anonymous and ephemeral\") — knowing the
URL still equals membership. The check here only guards against
attacker-supplied sessionIds with no backing row.

Full repo: pnpm typecheck / lint / test all green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 00:24:16 +02:00
..
components Centralize waypoint Yjs serialization in waypointFromYMap/waypointToYMap 2026-05-18 21:02:27 +02:00
jobs Add pg-boss background job queue with session expiry 2026-04-13 21:17:24 +02:00
lib fix(planner): require session row before accepting Yjs WebSocket upgrade 2026-05-26 00:24:16 +02:00
routes fix(planner): validate callback/returnUrl + cap session URL-param payloads 2026-05-26 00:05:47 +02:00
entry.client.tsx Add legal pages, ToS acceptance, and alpha banner 2026-04-18 00:08:48 +02:00
entry.server.tsx Consolidate Sentry config into shared package; fix inconsistencies 2026-04-18 00:30:09 +02:00
root.tsx Disable page zoom on iOS to prevent accidental pinch-to-zoom 2026-04-12 19:35:56 +02:00
routes.ts Cache BRouter segments client-side, fetch only the diff 2026-04-24 17:57:54 +02:00