Skip to content

Reset per-user state on logout, and validate messages in the recipe servers - #130

Merged
mehmetkose merged 2 commits into
mainfrom
security-audit-fixes
Oct 24, 2026
Merged

mehmetkose merged 2 commits into
mainfrom
security-audit-fixes

Conversation

@mehmetkose

Copy link
Copy Markdown
Owner

Fixes from a security audit of 4.20.0.

Library: logging out and switching accounts

  • close() also clears lastMessage, as it already cleared the send queue and a migrate() target.
  • New: feeds.reset(topic?), runs.clear(), agent.reset() (AG-UI), and a session option for createTabsWebSocket so tabs share a connection only within one user's session.
  • outbox.clear() removes every entry that exists when it's called. It used to keep entries timestamped ahead of the clearing tab's clock.
  • The authentication guide has a new "Logging out and switching accounts" section. SECURITY.md says servers should close a user's sockets when their session ends.

Recipes and examples

  • Every recipe server checks each message (JSON, a known type, typed fields) and closes only the sender's socket with 1003 on bad input, instead of throwing and stopping the server. Every server socket has an error listener.
  • Live notifications requires a SOCKET_SECRET of at least 32 characters and verifies tokens without throwing.
  • Team chat, whiteboard and delivery tracking clear their outbox on sign-out.
  • The Next.js, Astro and Remix demo servers cap messages at 64 KiB, accept only palette colors and on-pad cursor positions, and paint cursors with backgroundColor.

Behavior changes

  • Components rendering lastMessage show undefined after close() until a message arrives.
  • Size budgets raised: runs 1.9 → 2 kB, tabs 1.85 → 1.9 kB, AG-UI 3.85 → 3.95 kB, outbox 1.35 → 1.4 kB.

10 new regression tests fail on the old code and pass now (469 total). npm run check, check:package, size-limit, the example type checks and docs:build pass locally.

close() now clears lastMessage, and feeds.reset(), runs.clear() and
agent.reset() forget what the managers keep for the signed-in user.
createTabsWebSocket takes a session option so tabs share a connection
only within one user's session. outbox.clear() removes every entry that
exists when it's called, whatever its timestamp.

The authentication guide gets a section on logging out and switching
accounts, and SECURITY.md says servers should close a user's sockets
when their session ends.
Each recipe server parses and checks every message before using it and
closes only the sender's socket with 1003 on bad input, where a
malformed message used to stop the whole server. Every server socket
gets an error listener. The live notifications recipe requires a
SOCKET_SECRET of at least 32 characters and verifies tokens without
throwing. The team chat, whiteboard and delivery tracking recipes
clear their outbox on sign-out.

The Next.js, Astro and Remix demo servers cap messages at 64 KiB,
accept only palette colors and on-pad cursor positions, and their
cursors paint the color with backgroundColor.
@mehmetkose
mehmetkose merged commit 2c9096e into main Oct 24, 2026
7 checks passed
@mehmetkose
mehmetkose deleted the security-audit-fixes branch October 24, 2026 10:56
@mehmetkose mehmetkose mentioned this pull request Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant