fix(realtime): validate cursor and selection presence payloads - #8041
Merged
Merged
Conversation
The workflow cursor-update and selection-update handlers stored whatever object a client sent into the shared room presence hash and rebroadcast it to every peer, with no shape or size check. An authenticated user with read access to any workflow could park a multi-megabyte blob in shared Redis on every socket they opened and have the server fan it out on each presence broadcast. Both payloads are now rebuilt from a fixed field set before they reach room state or any broadcast, so unexpected keys cannot ride along - mirroring normalizeCellSelection in the table presence handler. Adds a defensive per-field length cap in updateUserActivity so future presence-bearing events inherit the bound, and marks UserPresence.cursor nullable to match the cleared-cursor value the client already sends.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
|
Contributor
There was a problem hiding this comment.
All reported issues were addressed across 4 files
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
The cap compared UTF-16 code units against a byte budget, so a multi-byte payload could pass the check and still land several times larger in the room hash. It now measures the UTF-8 bytes Redis actually stores. Raises the ceiling to 16384. A table cell selection carries four ids capped at 200 characters each, and multi-byte characters plus JSON escaping can expand a legitimate worst case to roughly 5 KB - above the previous 4096, so the old bound could have dropped real presence.
Collaborator
Author
Collaborator
Author
|
@cubic-dev-ai review this PR |
Contributor
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
This was referenced Sep 19, 2026
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
cursor-updateandselection-updatestored whatever object a client sent into the shared room presence hash and rebroadcast it to every peer, with no shape or size check. An authenticated user with read access to any workflow could park a multi-megabyte blob (bounded only by the 8 MiB Socket.IO frame ceiling) in shared Redis on every socket they opened, and have the server fan it out on every later presence broadcast.normalizeCellSelectionin the table presence handler, which already guards the sibling path — the workflow path was the unguarded one.updateUserActivityso future presence-bearing events inherit the bound. At 4096 it sits ~8x above the largest legitimate payload, so it never trims real presence.UserPresence.cursornullable. The client already sendscursor: nullto clear, and that null is genuinely stored — the type just didn't say so, which only type-checked before because the handler destructured an untyped payload.Type of Change
Testing
presence.test.tscovers both handlers: well-formed payloads, cleared cursor, unexpected-key stripping, and malformed/oversized rejection. Verified the tests can fail — reverting the handler turns 15 of the 20 red, while the 5 behavior-preservation cases stay green either way.bunx turbo run type-checkgreen across all 26 tasks;bun run lintand all 47 audits pass.Checklist