fix(devframe): validate authentication link origins - #325
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| const mod = await import('devframe/rpc/transports/ws-server') | ||
| loopbackCheck = mod.isLoopbackHostname |
There was a problem hiding this comment.
Let's move this to utils, avoid importing a whole module just for a utility
There was a problem hiding this comment.
Done in f82f8cd. Moved isLoopbackHostname (and isAllowedOrigin) into a new dependency-free devframe/utils/origin. instance-shell now imports validateOriginCandidate statically from there, so it no longer dynamically imports the whole crossws-carrying ws-server transport just for the loopback check.
| * non-HTTP(S) scheme, or an untrusted host). Forwarded headers are never | ||
| * consulted. | ||
| */ | ||
| function validateOriginCandidate( |
There was a problem hiding this comment.
Let's group all https / origin related utils
There was a problem hiding this comment.
Grouped into devframe/utils/origin: it now holds isLoopbackHostname, isAllowedOrigin, and validateOriginCandidate together. ws-server re-exports the two predicates so its public import path stays intact, and sse-server + the MCP fetch gate now import the check from the util directly rather than through the transport.
Address review: move isLoopbackHostname/isAllowedOrigin out of the crossws-carrying ws-server transport into a dependency-free devframe/utils/origin, and group the auth-link origin validation (validateOriginCandidate) alongside them. instance-shell now imports the validator statically instead of dynamically importing the whole transport module. ws-server re-exports both predicates to keep its public API path intact; sse-server and the MCP fetch gate import the check from the util directly.
…PI snapshots - Add the devframe/utils/origin alias to alias.ts (the source of truth that regenerates tsconfig.base.json paths), so the new subpath resolves to source in vitest and typecheck. - Add its tsnapi API snapshots and refresh the ws-server snapshot, whose representation shifts now that isAllowedOrigin/isLoopbackHostname are re-exports rather than local definitions (same public names).
Why
For handler- and middleware-owned hosts without an explicit public origin, the first inbound request permanently determined the origin used in the terminal's OTP magic link — Node middleware built it straight from the
Hostheader, and the fetch handler trusted the absolute request URL. An unauthenticated first request could therefore redirect the credential-bearing link to an attacker-controlled origin.Implements
plans/006-validate-auth-link-origin.md.What
isLoopbackHostname, reused from the WS transport), or its canonical origin must exactly match anallowedOriginsentry. Everything else — a raw inbound authority, a dynamicWsOriginRegistry, a disabled gate, forwarded headers — is ignored, and those deployments supply an explicitorigin.originand owned-listener (bound address/port) behavior are unchanged — both bypass request derivation.origin.Verification
pnpm --filter devframe typecheck→ exit 0pnpm lint→ exit 0Pre-existing, change-unrelated environment failures remain on the base branch (
@devframes/plugin-gitbuildEACCES,devframe-startertypecheck needing built workspace artifacts, and knip'sstarter/playgroundmodule-resolution errors); none touch the files in this change.This PR was created with the help of an agent.