The direct answer
Treat the opening handshake, each complete application message and each protected outbound response as separate admission decisions. Bind the connection to trusted session context, apply message bounds in the selected API’s actual units, and recheck current job access before releasing status. An allowed origin or responsive socket is not ongoing user or object authority.
Choose a status reader rather than an unlimited channel
A fictional AI console opens a connection while User A can read job J-A in workspace W-A. Membership changes before the next status request. Keeping the socket open must not preserve access that the application would deny on a new request.
This original worksheet selects the websockets 15.0.1 asyncio server reference, specifically serve and ServerConnection.recv. It does not describe an installed runtime, the latest maintained release or a deployed server. Before implementation, verify supported dependencies and the effective deployment separately.
The proposed browser endpoint permits only bounded job-status reads, one request and response at a time. It accepts no tool instructions, job creation, subscription fanout or external action. Its transport-specific decision differs from the window-message proposal receiver and provider-output stream consumer. Every card below is PROPOSED_UNRUN.
Keep origin admission separate from authentication
With an origins allowlist configured, the selected serve API supports exact origin strings and permits absent Origin when None is included in that list. Configure a single trusted origin O-A, with neither None nor the literal null origin admitted. O-A is an inert configuration label, not a header or endpoint constructed here.
RFC 6455 sections 10.1–10.2 distinguish browser-origin protection from clients capable of fabricating Origin. Therefore this compatibility profile does not prove the peer is a browser or identify its user. Do not replace session authentication with an origin match or a familiar hostname suffix.
Require independently supported session authentication during the opening handshake, with a server-owned connection record C-A binding the current principal, session association and W-A. The authentication implementation, cookies, TLS deployment and proxy behavior remain unverified prerequisites. Reject malformed or ambiguous handshake evidence under application policy; this article makes no undocumented claim about the library’s duplicate-header parser. Never force a successful upgrade around failed authentication or origin checks.
Name the units in the receive profile
The reference documents max_size as incoming-message bytes and max_queue as received-frame buffer high/low watermarks. Its ordinary recv reassembles fragments before returning the whole message, returns text as str and binary as bytes by default, and rejects concurrent receivers. These are selected-version API facts, not generic socket behavior.
Propose max_size=2048 bytes, max_queue=(4,1), open_timeout=5 seconds and compression=None, with no additional extensions. The reference documents compression=None as disabling permessage-deflate and open_timeout as opening-handshake time. These invented settings are review choices, not measured safe production defaults.
Two KiB is a complete incoming-message allowance, not a Unicode-character count. Four is a frame-buffer high-water mark, not permission for four application requests or a hard whole-process memory ceiling. A fragmented message can occupy several frames. Choose one recv owner, retain default decoding and admit only its text result; binary input stays unsupported. This profile does not use recv_streaming or process individual fragments.
Admit only complete requests, then authorize the response
After a complete text message arrives, require the exact allowed status-read envelope and bounded field values. A job label is a requested object reference, never a credential or instruction to switch C-A into W-B. Resolve it through trusted context and authorize the present principal for that exact job.
OWASP’s WebSocket guidance recommends explicit origin allowlists, session-lifecycle handling, message-level authorization, input limits and resource controls. Apply those concerns after the handshake as well as during it. A successful parse is not the permission decision.
For the positive card, C-A remains valid and a complete permitted text request selects J-A. Produce only its minimized status, not the model prompt, document contents or another job’s metadata. Before outbound admission, re-establish current session and J-A read rights against the same response association. An incoming request admitted earlier cannot authorize a delayed disclosure after revocation.
Coordinate that final rights decision with protected response admission using a supported design. A separate check followed by an unprotected enqueue can race revocation. Define the local cutoff precisely: data already admitted into transport buffers or delivered before the cutoff cannot be recalled by changing C-A or closing the socket.
Review eight inert connection and message cards
| Inert condition | Proposed application decision |
|---|---|
| O-A, valid bound session, complete bounded text request for permitted J-A | Admit request; release minimized status only after current outbound checks |
| Unexpected origin | Deny this browser endpoint’s handshake admission |
| Missing, null, malformed or ambiguous origin evidence | No admission under the strict compatibility policy; no substring fallback |
| O-A matches but session authentication fails | Deny; origin cannot supply a principal |
| Text envelope selects another workspace or unauthorized job | Deny object access without changing C-A’s authority |
| Request admitted, then membership/session association changes before outbound admission | Suppress protected response; invalidate affected connection path under policy |
| Text arrives fragmented within the message allowance, or input is binary/oversize | Wait for complete text before checks; reject unsupported type or size failure, never authorize a fragment |
| Incomplete message, queue pressure, receive error or closing connection | No inferred application completion; stop or hold under bounded lifecycle policy |
Bound connection lifetime and report delivery honestly
One small message does not bound an unlimited sequence of messages. Propose separate per-principal connection limits, a finite application request allowance, a complete-message deadline and an outbound encoded-status ceiling of 1024 bytes. These controls require implementation evidence beyond this worksheet; max_size alone does not enforce outbound size, total allocations, CPU or connection lifetime.
RFC 6455 distinguishes fragmented messages and interleaved control frames; Ping/Pong can indicate responsiveness. Neither a Pong nor a fresh frame establishes a completed status request, valid session or renewed application deadline. A send attempt or clean close also does not prove the interface displayed a result or that an underlying AI job completed.
On logout or expired authority, stop new application admissions and close the affected connection through the supported lifecycle. Do not claim cancellation of already admitted jobs, zero later network traffic or recall of earlier bytes. Keep minimized connection/case/disposition records rather than reusable session material or message contents.
No browser, socket, server, client, frame, compression, parser or runtime fixture was exercised for these cases. Boundary is prelaunch and does not claim a shipped WebSocket authorization service. Its eight historical mock policy checks and separate synthetic JSON-export checks concern different behavior.
Primary sources
Official references supporting the guidance. Examples in this guide are synthetic and are not reports of a production incident.