agentsclimarketplace

Websocket security

Skill ShieldNet-360/secure-vibe/skills/websocket-security

SecureVibe — prevention-first security for AI-written code. Signed SKILL.md knowledge that makes AI coding assistants write secure code at generation time, plus a deterministic CI gate. Offline · keyless · Ed25519-signed. By ShieldNet360.

Install
npx -y skills add ShieldNet-360/secure-vibe --skill websocket-security

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Secure WebSocket endpoints: Origin validation, auth on handshake, message size/rate limits, wss-only, reconnection backoff

SKILL.md

8.0 KB, ~1.7k tokens by cl100k_base, as published. Nobody here has run it

WebSocket Security

Rules (for AI agents)

ALWAYS

  • Validate the Origin header on the WebSocket upgrade handshake against an allowlist. CORS does not apply to WebSockets — the browser will happily upgrade cross-origin and let JavaScript on attacker.com open wss://api.example.com/ws with the user's cookies (Cross-Site WebSocket Hijacking).
  • Require authentication on the handshake itself, not as the first message after connect. Either:
    1. Cookie-based auth on the HTTP upgrade (and CSRF-protect by verifying Origin), or
    2. A short-lived signed token (5–10 minute lifetime) in the Sec-WebSocket-Protocol subprotocol header, or
    3. A signed query parameter token. Never trust a subscribe / auth message after the upgrade — by that point the connection has already been opened with the authenticated cookie context.
  • Use wss:// only in production. Plain ws:// over the open internet exposes session tokens, message contents, and CSRF primitives to any on-path observer.
  • Enforce max message size at the server (typical: 32 KiB for chat, 256 KiB for collaborative editing, much higher only when the use case demands it and the auth bar is high). Without a limit, a single open socket can OOM the server.
  • Enforce a message rate limit per connection (e.g. 60 messages/minute) and a connection rate limit per source IP / per authenticated user. Real-time abuse (chat spam, presence ping flood) is a frequent DoS source.
  • Implement ping / pong heartbeats (every 20–30 s) and close the connection on missed pong. Half-open TCP sockets accumulate behind load balancers otherwise.
  • On the client side, use bounded exponential backoff for reconnection (e.g. base 1 s, factor 2, max 60 s, jitter ±20%). A naïve setTimeout(connect, 0) reconnect loop melts the server during outages.
  • Treat each WebSocket message as a separate request for the purposes of input validation and authorization. The user's permissions can change after the socket is open (logout, role change, account lock) — re-check on each privileged action.
  • Object-level-authorize the subject / resource id carried in each message, not just the action type. A frame like {"action":"write","subjectId":"X"} must be checked so the connection's handshake-authenticated principal may actually act on X. An authenticated socket must not be able to assert an arbitrary subject id per frame — that is per-frame BOLA, and the forged id reaches any consumer downstream of the socket (queue / topic / fan-out) that trusts it.

NEVER

  • Skip Origin validation because "it's a WebSocket, CORS doesn't apply." That's exactly why you have to do it yourself. The documented attack is Cross-Site WebSocket Hijacking, demonstrated publicly in 2013 and still common in 2024 bug-bounty reports.
  • Use a session cookie as a long-lived WebSocket token. If the WS connection is supposed to survive multiple tabs / pages, issue a refreshable short-lived JWT in the subprotocol; don't rely on the cookie sticking around forever.
  • Allow arbitrary subprotocols from the client to influence server-side routing without an allowlist. Subprotocol negotiation is attacker-controlled.
  • Run WebSocket handlers in the same process / thread pool as HTTP request handlers without sizing limits — a slow-loris-style WebSocket can starve all HTTP work.
  • Expose internal cluster topology in WebSocket messages (e.g. {"server_id": "pod-prod-42"}). Internal IDs are reconnaissance material on a chatty real-time channel.

KNOWN FALSE POSITIVES

  • Public chat / presence endpoints that are intentionally open to any origin must still enforce per-connection rate limits and a per-source-IP cap; they may legitimately permit Origin: null for desktop / mobile clients.
  • Mobile / desktop native clients send no Origin header. Decide upfront whether to allow them (and apply a different auth mode like device-cert + bearer token) or to reject them outright.
  • Service-to-service WebSockets (e.g. Kafka WebSocket bridge, Apache Pulsar) inside a private VPC may legitimately use ws:// with mTLS handled at the network layer.

Context (for humans)

WebSockets are the long-lived sibling of HTTP. Most of the controls HTTP gets for free (CORS, CSP, per-request auth) do not apply out-of-the-box, and frameworks that wrap WebSockets behind a higher- level API (Socket.IO, SignalR, Phoenix Channels) hide the upgrade mechanism enough that developers forget to harden it.

The two recurring incident classes are:

  1. Cross-Site WebSocket Hijacking — missing Origin check + cookie auth → attacker.com opens a WS with the user's cookies and reads their stream.
  2. Resource exhaustion — no size / rate / connection limit + a chatty protocol → trivial DoS.

Both are simple fixes, but both are easy to forget when generating a quick chat / collab feature. This skill mirrors the OWASP cheat sheet plus the operational must-haves (heartbeats, backoff).

Verify & lock (triaging a finding)

A scanner/review hit is a candidate, not a confirmed bug. Confirm it, fix it, then lock it so it can't come back.

  1. Confirm it's real (probe the handshake and the first messages). Replay the WebSocket upgrade with a hostile context: send a foreign Origin: https://attacker.example header (and the victim's session cookie if cookie auth is in play), and separately try the upgrade with no token / an expired token. Real if the socket reaches OPEN and starts streaming data — CSWSH is confirmed when a cross-origin page can establish the connection and read the user's stream; broken handshake-auth is confirmed when an unauthenticated upgrade succeeds and only a later auth/subscribe message gates access. For resource limits, hold one socket open and fire an oversized frame and a rapid message burst — real if neither is rejected (no size cap, no per-connection rate limit). A false positive: the upgrade is refused (4xx / close) for the disallowed Origin and the missing/expired token, and oversized or floods are dropped.
  2. Fix, then lock with a regression test (unit or integration — dev's call): assert a handshake carrying a disallowed Origin is rejected and one without a valid token is rejected, while an allowlisted Origin + valid token connects; assert a frame over the max size and a burst past the rate limit are closed/dropped, and that each privileged message is re-authorized (a revoked/role-changed user is denied) — plus a benign case: legitimate origin, valid token, normal-sized message at normal cadence still succeeds. Commit it to CI so the guard can't be silently dropped in a later refactor.

References

What ships with it: 2 files

8.9 KB alongside SKILL.md

tests/

Keep looking

Skills are one crate of 326,970. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.