Skip to content

Validate WebSocket Origin to secure the dev REPL server#83

Merged
bbatsov merged 2 commits into
masterfrom
secure-origins
Jun 28, 2026
Merged

Validate WebSocket Origin to secure the dev REPL server#83
bbatsov merged 2 commits into
masterfrom
secure-origins

Conversation

@bbatsov

@bbatsov bbatsov commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

WebSocket handshakes aren't subject to the same-origin policy, so today any page a developer has open in another tab can connect to the REPL server. With multi-client takeover that's worse than it sounds - a drive-by page can become the active client, receive the eval-js stream, and inject frames. This adds an Origin allowlist.

By default only local origins (localhost, 127.0.0.1, [::1], any port, http or https) are accepted. Non-browser clients send no Origin header and are always allowed, so the Node/Deno/Bun path is unaffected (the integration test still passes). Serving from elsewhere - a LAN IP for phone testing, a custom dev domain - is a :allowed-origins away; it takes a single origin, a collection, a predicate, or :all to opt out.

This is a deliberate secure-by-default behavior change: setups that served the app from a non-local origin will now get a 403 until they set :allowed-origins. Noted in the README and changelog.

Came out of an adversarial review pass - the notable catch was building the origin policy before binding the listen port, so a bad :allowed-origins fails fast instead of leaking an unstoppable server.

bbatsov added 2 commits June 28, 2026 11:29
WebSocket handshakes aren't bound by the same-origin policy, so any page a
developer has open could otherwise connect to the REPL server and, with
takeover, drive it. The server now checks the Origin header and accepts only
local origins by default; the new :allowed-origins option widens it. It takes a
single origin, a collection, a predicate, or :all. Non-browser clients send no
Origin and are unaffected, so the Node integration path keeps working.

The origin policy is built before the listen port is bound, so a bad
:allowed-origins value fails fast instead of leaking a server with no stop
handle.
@bbatsov bbatsov merged commit 5ddbf18 into master Jun 28, 2026
1 check passed
@bbatsov bbatsov deleted the secure-origins branch June 28, 2026 08:30
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