Skip to content

feat(channels): add validateWebSocketOrigin helper for WS upgrade hooks#129

Open
aaronjmars wants to merge 1 commit into
vercel:mainfrom
aaronjmars:security/websocket-origin-validation
Open

feat(channels): add validateWebSocketOrigin helper for WS upgrade hooks#129
aaronjmars wants to merge 1 commit into
vercel:mainfrom
aaronjmars:security/websocket-origin-validation

Conversation

@aaronjmars

Copy link
Copy Markdown

Summary

eve's WS() upgrade hook can already reject a handshake by returning a Response, but the framework ships no helper to validate the Origin — so cross-site WebSocket hijacking (CWE-1385) / DNS-rebinding (CWE-346) defense is left to each channel author to hand-roll, and the safe default is easy to miss. The production server binds 0.0.0.0 and accepts a WS handshake on any matched route, so a malicious page in a victim's browser can complete a same-credentials handshake and drive the agent unless the author wrote an Origin check.

This adds a small, opt-in, additive helper — no default behavior changes.

API

import { defineChannel, WS, validateWebSocketOrigin } from "eve/channels";

WS("/ws", () => ({
  upgrade(request) {
    return validateWebSocketOrigin(request, {
      allowedOrigins: ["https://app.example.com"],
    });
  },
  message(peer, message) { /* ... */ },
}));
  • Returns a 403 Response to reject a missing, opaque (Origin: null), or non-allowlisted Origin; returns undefined to proceed — matching the hook's Response | void contract.
  • Origins are compared by normalized URL.origin (scheme + host + non-default port), so port / trailing-slash / case differences don't matter.
  • A missing Origin is rejected by default (strict posture); allowNoOrigin: true permits non-browser clients (which never send one). An Origin check bounds the browser threat only — documented as one layer of defense, not authentication.

Changes

  • packages/eve/src/channel/websocket-origin.ts — helper + ValidateWebSocketOriginOptions
  • exported from eve/channels (public/channels/index.ts)
  • docs/channels/custom.mdx — "Validating the Origin" section
  • 7 colocated unit tests + a patch changeset

Verification

pnpm typecheck, pnpm lint, pnpm fmt, pnpm guard:invariants, and the full pnpm --filter eve test:unit (3637 tests) all pass locally. I did not run the e2e/scenario suites — they require model-provider credentials — and this change is pure request-header logic covered at the unit tier.

Happy to adjust the API (e.g. a predicate form for subdomain matching) if you'd prefer a different surface.

The WS() upgrade hook can already reject a handshake by returning a
Response, but eve ships no helper to validate the Origin, so cross-site
WebSocket hijacking / DNS-rebinding defense is left to each channel author
to hand-roll. The production server binds 0.0.0.0 and accepts a handshake
on any matched WS route, so a malicious page in a victim's browser can
otherwise complete a same-credentials handshake and drive the agent.

validateWebSocketOrigin(request, { allowedOrigins }) enforces an Origin
allowlist from inside the upgrade hook: it returns a 403 Response to reject
a missing, opaque, or non-allowlisted Origin and undefined to proceed,
matching the hook's Response | void contract. Opt-in and additive, no
default behavior changes. Origins are compared by normalized URL.origin;
allowNoOrigin permits non-browser clients that send no Origin header.

- packages/eve/src/channel/websocket-origin.ts: helper + options type
- exported from eve/channels (public/channels/index.ts)
- docs/channels/custom.mdx: "Validating the Origin" section
- colocated unit tests (7) + changeset (patch)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Aaron Elijah Mars <aaronjmars@proton.me>
@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

@aaronjmars is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

@AndrewBarba

Copy link
Copy Markdown
Collaborator

This is great thank you. we are working hard to enable outside contribution - need safe ways to run our ci suite, etc. will provide an update on Monday

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.

2 participants