🤖 feat: mux module — add per-workspace auth token for CSWSH protection#728
🤖 feat: mux module — add per-workspace auth token for CSWSH protection#728ibetitsmike merged 4 commits intomainfrom
Conversation
Generate a random 64-char token per workspace via random_password. Inject into the Mux server process as MUX_SERVER_AUTH_TOKEN (coder_env) and into the browser via ?token= in coder_app.url. The frontend already extracts this parameter and persists it to localStorage. This closes the last-mile deployment gap for coder/security#120: the origin-check + auth-token combination blocks cross-site WebSocket hijacking from same-site origins (e.g. other workspace apps). Bump module version references to 1.1.0.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 55be495ef4
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
random_password.result is unknown during plan, causing 'Unknown condition value' errors. Tests that check the URL or token value must use apply.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f3af56b022
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Pass the generated auth token to each mux process via process-scoped MUX_SERVER_AUTH_TOKEN in run.sh instead of creating a global coder_env entry. This avoids collisions when multiple mux module instances target the same agent. Also tighten terraform tests to assert that the URL token value matches the generated token, and update remaining README examples to 1.1.0.
|
@codex review |
|
Codex Review: Didn't find any major issues. 🎉 ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
|
@codex review Addressed prior feedback and resolved the related threads. |
|
Codex Review: Didn't find any major issues. You're on a roll. ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
Summary
Add per-workspace authentication token wiring to the Mux Coder module, closing the last-mile deployment gap for cross-site WebSocket hijacking (CSWSH) protection identified in coder/security#120.
Background
When Mux runs as a Coder workspace app, it is accessible via Coder's subdomain proxy (e.g.,
mux--ws--user.apps.coder.com). Without an auth token, a malicious same-site origin (another user's workspace app on the same*.coder.comdomain) can hijack the WebSocket session and execute arbitrary commands via the oRPC API.The Mux application itself already implements:
MUX_SERVER_AUTH_TOKENor--auth-token, and the browser frontend extracts?token=from the URL and persists it to localStorageWhat was missing was module-level token generation and browser/backend wiring.
Implementation
random_password.mux_auth_tokengenerates a 64-character token per module instance.run.shlaunches mux with a process-scopedMUX_SERVER_AUTH_TOKENenvironment variable.coder_app.mux.urlincludes?token=<secret>so first launch from Coder passes the token to the browser for bootstrap/persistence.To avoid cross-instance breakage, this change intentionally does not use a shared
coder_envkey. Multiplecoder/muxmodule instances can target the sameagent_id(differentslug/port), and a single global env key would collide. Process-scoped env keeps each instance's backend token aligned with its app URL token.Validation
terraform fmt -check -diffinregistry/coder/modules/muxterraform testinregistry/coder/modules/mux(8 passed, 0 failed)MUX_SERVER_AUTH_TOKENusing the generated token.Generated with
mux• Model:anthropic:claude-opus-4-6• Thinking:xhigh