Skip to content

fix(ws,router): post-merge audit hardening for the upgrade seam (#13) - #92

Merged
devin-ai-integration[bot] merged 1 commit into
mainfrom
devin/1792395841-ws-audit
Oct 19, 2026
Merged

devin-ai-integration[bot] merged 1 commit into
mainfrom
devin/1792395841-ws-audit

Conversation

@espetro

@espetro espetro commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Post-merge audit follow-up for issue #13 (@chttp/ws upgrade seam). The package and most audit items (handler error boundaries, linear feed(), _fchunks assembly, backlog cap) already landed on main; this PR closes the remaining findings.

  • WsRouter.allowOrigin(origin) — chainable exact-match allowlist. Once at least one origin is registered, handshakes with a missing or unlisted Origin header are rejected 403. Default stays open (same as ws), documented as a CSWSH risk for cookie-authenticated apps.
  • Sec-WebSocket-Key format check — must be base64 decoding to a 16-byte nonce (RFC 6455 4.2.1); else 400.
  • Peer close reason UTF-8 validation — a close frame whose reason fails the decode/encode round-trip is answered 1007.
  • Router seam — upgradeHandler() now catches a throwing dispatch and destroys the socket instead of crashing the process; UpgradeFn is re-exported; contracts/upgrade-contract.md dispatch semantics updated to match.
  • Docs honesty — docs/websocket.md handshake table gains the 400/403 rows plus an Origin allowlist section; the "frames rejected from the header alone" claim is narrowed to single frames (fragmented messages buffer up to ~maxPayload before the 1009 fires); packages/ws/README.md now wires server.on("upgrade", app.upgradeHandler()) since serve() never attaches it.

Not changed, deliberately: Connection header checking is dead code on node:http (the server only emits "upgrade" when the token is already present — verified by probe; docs say so). Close-handshake timeout remains unimplemented and is now listed as a known limitation.

Tests

packages/ws: +5 test blocks — key format 400s, token-list/case-insensitive headers, origin allowlist 101/403, fragmented invalid UTF-8 → 1007, close-reason invalid UTF-8 → 1007, single-write maxPending refusal → 1009, zero-length text/binary round-trip. 21/21 pass.

Gates: pnpm --filter @chttp/router test green, pnpm lint clean (pre-existing warnings only), scripts/scriptc-gate.sh 10/10 gates at 100%, pnpm smoke:ws:ffi builds the vendored ws-echo ELF and serves FFI routes.

Refs #13

Link to Devin session: https://app.devin.ai/sessions/b44c98ebb2794946b91a700970496547
Open in Devin Desktop: https://app.devin.ai/desktop/session/b44c98ebb2794946b91a700970496547?variant=devin
Requested by: @espetro

- WsRouter.allowOrigin: exact-match Origin allowlist; once set, missing
  or unlisted Origin headers reject the handshake with 403 (CSWSH).
- Sec-WebSocket-Key must decode from base64 to a 16-byte nonce
  (RFC 6455 4.2.1); Connection needs no check because node:http only
  emits upgrade when the token is present.
- Peer close reason is UTF-8 validated; invalid closes with 1007.
- upgradeHandler() catches a throwing dispatch and destroys the socket
  instead of crashing the process; UpgradeFn re-exported.
- Docs: handshake table + origin section, fix the header-only 1009
  overclaim for fragmented messages, honest timeout limitation; README
  wires server.on("upgrade"). Tests: key format, token-list Connection,
  origin allowlist, fragmented UTF-8, maxPending feed refusal,
  zero-length messages.
@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying chttpjs with  Cloudflare Pages  Cloudflare Pages

Latest commit: bd93e23
Status: ✅  Deploy successful!
Preview URL: https://ac806100.chttpjs.pages.dev
Branch Preview URL: https://devin-1792395841-ws-audit.chttpjs.pages.dev

View logs

@devin-ai-integration
devin-ai-integration Bot merged commit 0fb7087 into main Oct 19, 2026
3 checks passed
@devin-ai-integration
devin-ai-integration Bot deleted the devin/1792395841-ws-audit branch October 19, 2026 07:53
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