feat(channels): add validateWebSocketOrigin helper for WS upgrade hooks#129
Open
aaronjmars wants to merge 1 commit into
Open
feat(channels): add validateWebSocketOrigin helper for WS upgrade hooks#129aaronjmars wants to merge 1 commit into
aaronjmars wants to merge 1 commit into
Conversation
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>
|
@aaronjmars is attempting to deploy a commit to the Vercel Team on Vercel. A member of the Team first needs to authorize it. |
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
eve's
WS()upgradehook can already reject a handshake by returning aResponse, but the framework ships no helper to validate theOrigin— 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 binds0.0.0.0and 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 anOrigincheck.This adds a small, opt-in, additive helper — no default behavior changes.
API
403Responseto reject a missing, opaque (Origin: null), or non-allowlistedOrigin; returnsundefinedto proceed — matching the hook'sResponse | voidcontract.URL.origin(scheme + host + non-default port), so port / trailing-slash / case differences don't matter.Originis rejected by default (strict posture);allowNoOrigin: truepermits non-browser clients (which never send one). AnOrigincheck bounds the browser threat only — documented as one layer of defense, not authentication.Changes
packages/eve/src/channel/websocket-origin.ts— helper +ValidateWebSocketOriginOptionseve/channels(public/channels/index.ts)docs/channels/custom.mdx— "Validating the Origin" sectionpatchchangesetVerification
pnpm typecheck,pnpm lint,pnpm fmt,pnpm guard:invariants, and the fullpnpm --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.