Individual skill
websocket-security
Securing the WebSocket upgrade and the frames after it: Origin validation against Cross-Site WebSocket Hijacking, authenticating the handshake rather than the first message, the ticket pattern for browsers that cannot set headers, per-frame authorization, and resource limits on a connection that stays open. Use when generating a WebSocket, Socket.IO, SignalR, or Phoenix Channels server, wiring real-time messaging, presence, or collaborative editing, or reviewing a /ws endpoint.
dist/agent-skills/.agents/skills/websocket-security/SKILL.md
Source commit eaba88102d91df65a9aa6397e8507c315c018f5e
What was checked
- Matches the observed repository HEAD
- Yes
- Scanner rules are current
- Yes
- Repository scan complete
- No
- Skill scan complete
- No
- Observed behavior
- Network or broad shell
- Last checked
- Nov 6, 2026
These are observations at the recorded commit, not a guarantee of safety. Review the source before running it.
Install this skill
Choose an agent in your Stack or copy a command below. Commands fetch the pinned commit and copy only this skill directory. Existing destinations are refused. Copying a command does not install anything.
An install command is unavailable: current rules, complete repository and skill scans, an eligible behavior level and a permitted license are required.
Repository context
- Repository stars (not skill ratings)
- 23
- Repository last updated
- Aug 14, 2026
- License
- MIT
Observed agent integration: No specific integration evidence. Standard SKILL.md installation does not imply verified compatibility.
Files and excerpt
File metadata and permitted, redacted excerpts come from the recorded scan. Source links are pinned to that commit.
Browse files
SKILL.mdcore · 6,957 bytesSKILL.mdcore · 6,957 bytesSKILL.mdcore · 6,957 bytesSKILL.mdcore · 6,957 bytesSKILL.mdcore · 6,957 bytesmetadata.jsonasset · 1,535 bytesreferences/limits-and-handshake.mddoc · 6,048 bytesreferences/verifying-findings.mddoc · 3,655 bytes
Read excerpt
<!-- Native skill bundle for agent-skills (cross-tool convention). Generated by `secure-vibe dev regenerate`. -->
<!-- Do not edit by hand; the source of truth is skills/websocket-security/SKILL.md. -->
# WebSocket Security
Securing the WebSocket upgrade and the frames after it: Origin validation against Cross-Site WebSocket Hijacking, authenticating the handshake rather than the first message, the ticket pattern for browsers that cannot set headers, per-frame authorization, and resource limits on a connection that stays open. Use when generating a WebSocket, Socket.IO, SignalR, or Phoenix Channels server, wiring real-time messaging, presence, or collaborative editing, or reviewing a /ws endpoint.
## ALWAYS
- Validate the **`Origin` header** on the upgrade handshake against an allowlist, and understand precisely what that buys: the browser sets `Origin` and script cannot forge it, so the check stops **Cross-Site WebSocket Hijacking** — a page on `attacker.com` opening `wss://api.example.com/ws` and inheriting the user's cookies. It buys nothing against a non-browser client, which sets any header it likes. Origin is a CSRF control, not authentication. The same-origin policy and CORS preflight do not apply to the upgrade at all, which is why this check must be written by hand.
- Authenticate the **handshake**, not the first frame. Once the upgrade completes the connection exists, has consumed the user's cookie context, and is already a resource the caller controls. A `subscribe` or `auth` message afterwards is too late.
- For a browser client, pick one of two mechanisms, because the browser `WebSocket` constructor **cannot set request headers** — there is no `Authorization` header available to you: 1. **Cookie on the upgrade** plus the `Origin` check above as the CSRF control, or 2. A **single-use ticket**: the authenticated page calls an ordinary HTTP endpoint, receives a short-lived opaque ticket bound to the user and to the intended resource, passes it in the URL, and the server **redeems and invalidates it at handshake time**. A ticket is safe in a URL precisely because replaying it fails.
- Re-authorize **every frame**, both the action and the subject it names. A frame like `{"action":"write","subjectId":"X"}` must be checked against the principal established at handshake — an authenticated socket must never be able to assert an arbitrary subject id per frame. That is per-frame BOLA, and the forged id reaches every consumer downstream of the socket that trusts it. Permissions also change while the connection is open: logout, role change, account lock, token expiry. A socket opened an hour ago carries an authorization decision an hour old.
- Bound the connection: maximum frame and message size, messages per second per connection, concurrent connections per user and per source address, and total connection lifetime after which the client must re-handshake. A WebSocket is an allocation that persists, so every limit HTTP gets per-request must be re-expressed per-connection. Concrete starting values, and the backpressure and heartbeat settings, are in `references/limits-and-handshake.md`.