Skip to content

Hotfix: Backport host/origin validation to requests and websocket connections#34011

Merged
ghengeveld merged 10 commits into
v7from
origin-validation-v7
Mar 6, 2026
Merged

Hotfix: Backport host/origin validation to requests and websocket connections#34011
ghengeveld merged 10 commits into
v7from
origin-validation-v7

Conversation

@ghengeveld
Copy link
Copy Markdown
Member

@ghengeveld ghengeveld commented Mar 4, 2026

What I did

This is a backport of #33835 for Storybook v7.6.

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

  • Run npx ngrok http 6006
  • Verify that the ngrok URL serves an Invalid host error
  • Update .storybook/main.ts to set core.allowedHosts to include the ngrok hostname (no protocol), then restart Storybook
  • Verify that the ngrok URL serves Storybook properly, and it works

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This pull request has been released as version 0.0.0-pr-34011-sha-c45b0f3f. Try it out in a new sandbox by running npx storybook@0.0.0-pr-34011-sha-c45b0f3f sandbox or in an existing project with npx storybook@0.0.0-pr-34011-sha-c45b0f3f upgrade.

More information
Published version 0.0.0-pr-34011-sha-c45b0f3f
Triggered by @ghengeveld
Repository storybookjs/storybook
Branch origin-validation-v7
Commit c45b0f3f
Datetime Fri Mar 6 09:49:06 UTC 2026 (1772790546)
Workflow run 22757942644

To request a new release of this pull request, mention the @storybookjs/core team.

core team members can create a new canary release here or locally with gh workflow run --repo storybookjs/storybook publish.yml --field pr=34011

Summary by CodeRabbit

  • New Features

    • Host validation for HTTP and WebSocket connections with origin and token checks.
    • New allowedHosts configuration; shown in startup logs (lists hosts or "all (insecure)").
    • Server considers local and network addresses when validating connections and returns 403 for invalid hosts/origins.
    • Runtime warning when binding to 0.0.0.0 without allowedHosts configured.
  • Tests

    • Expanded tests covering host/origin and token validation scenarios.

@ghengeveld ghengeveld requested a review from yannbf March 4, 2026 13:07
@ghengeveld ghengeveld self-assigned this Mar 4, 2026
@ghengeveld ghengeveld added the maintenance User-facing maintenance tasks label Mar 4, 2026
@ghengeveld ghengeveld added the ci:daily Run the CI jobs that normally run in the daily job. label Mar 4, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 4, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds host validation for HTTP requests and WebSocket upgrades, propagates allowedHosts/localAddress/networkAddress into Vite and startup outputs, changes server-channel APIs to accept an options object (token + host context), updates related types, tests, and dependencies.

Changes

Cohort / File(s) Summary
Host validation module
code/lib/core-server/src/utils/getHostValidationMiddleware.ts
New module with HostValidationOptions, DEFAULT_ALLOWED_HOSTS, isValidHost, and getHostValidationMiddleware; enforces Host header checks and returns 403 for invalid hosts.
WebSocket server channel & tests
code/lib/core-server/src/utils/get-server-channel.ts, code/lib/core-server/src/utils/__tests__/server-channel.test.ts
API changed to accept ServerChannelTransportOptions (token + host context). Upgrade flow now parses URL, validates origin/host and token, logs warnings, and returns 403 on failure; tests updated for new options and validation cases.
Dev server integration
code/lib/core-server/src/dev-server.ts, code/lib/core-server/src/build-dev.ts, code/builders/builder-vite/src/vite-server.ts
Compute and pass local/network addresses earlier; extract allowedHosts from core presets; warn when host is 0.0.0.0 without allowedHosts; propagate allowedHosts into Vite server config and startup flow.
Startup output & types
code/lib/core-server/src/utils/output-startup-information.ts, code/lib/types/src/modules/core-common.ts
Add allowedHosts to startup output options and CoreConfig; add localAddress and networkAddress to BuilderOptions types.
Token validation utilities
code/lib/core-server/src/utils/validate-websocket-token.ts
Rename parameter to requestToken and adjust byte conversion to Uint8Array for timingSafeEqual usage (no logic change).
Dependencies, typings & tooling
code/package.json, code/lib/core-server/package.json, code/jest.config.base.js, code/lib/core-server/src/typings.d.ts
Add host-validation-middleware dependency and ambient module typing; include it in Jest transform list.
Minor formatting
code/builders/builder-manager/src/utils/template.ts
Non-functional formatting change to a JSON.stringify call.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Server as HTTP/WS Server
    participant Middleware as Host Validation Middleware
    participant Upgrade as WS Upgrade Handler
    participant Logger

    Client->>Server: HTTP upgrade request (Host header, Origin, token in URL)
    Server->>Middleware: validate Host header
    alt Host valid
        Middleware-->>Server: next()
        Server->>Upgrade: handleUpgrade(request)
        Upgrade->>Upgrade: parse URL & extract requestToken
        Upgrade->>Upgrade: isValidHost(originHost, options)
        Upgrade->>Upgrade: isValidToken(requestToken, expectedToken)
        alt Token & Origin valid
            Upgrade-->>Client: complete WS upgrade
            Upgrade->>Server: emit 'connection'
        else invalid token/origin
            Upgrade-->>Client: 403 Forbidden, terminate socket
            Upgrade->>Logger: warn(...)
        end
    else Host invalid
        Middleware-->>Client: 403 Forbidden "Invalid host"
        Middleware->>Logger: warn(...)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@code/lib/core-server/src/build-dev.ts`:
- Around line 104-117: The warning uses the stale allowedHosts value captured
from the first presets.apply('core', {}) call; update the code to re-read
core.allowedHosts from presets.apply('core', {}) (or from the second-pass
presets where core is finalized) immediately before emitting the logger.warn and
any startup output so the check uses the final allowedHosts value; locate the
allowedHosts variable and the logger.warn block and replace its condition to
reference the freshly obtained allowedHosts (or a helper like
resolveAllowedHosts()) used later at startup to ensure accurate warnings about
--host 0.0.0.0.

In `@code/lib/core-server/src/utils/getHostValidationMiddleware.ts`:
- Around line 51-53: Update the misleading comment in
getHostValidationMiddleware: change the sentence that claims "Requests with no
Host header (e.g. same-origin navigation, GET from address bar) are not allowed"
to accurately state that modern browsers and address-bar navigations normally
include a Host header (HTTP/1.1+), and clarify that missing Host headers occur
only for older/non-HTTP/1.1 clients or malformed requests; ensure this revised
note appears alongside the getHostValidationMiddleware validation description so
future maintainers are not confused.
- Around line 35-39: The current early-return in getHostValidationMiddleware
that treats options.host === '0.0.0.0' and allowedHosts.length === 0 as valid
must be removed; instead, do not bypass host validation for 0.0.0.0—either
remove that conditional entirely or change the logic to only allow all hosts
when an explicit wildcard entry (e.g., '*' or a documented allow-all marker)
exists in allowedHosts; update the validation flow around options.host and the
allowedHosts check so Host headers are always validated unless explicitly
configured to allow all.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c94bf7ad-279e-467b-a00e-cf4fa4d033e4

📥 Commits

Reviewing files that changed from the base of the PR and between 736b0f1 and 1f3f0b0.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (9)
  • code/builders/builder-vite/src/vite-server.ts
  • code/lib/core-server/src/build-dev.ts
  • code/lib/core-server/src/dev-server.ts
  • code/lib/core-server/src/utils/get-server-channel.ts
  • code/lib/core-server/src/utils/getHostValidationMiddleware.ts
  • code/lib/core-server/src/utils/output-startup-information.ts
  • code/lib/core-server/src/utils/validate-websocket-token.ts
  • code/lib/types/src/modules/core-common.ts
  • code/package.json

Comment thread code/lib/core-server/src/build-dev.ts
Comment thread code/lib/core-server/src/utils/getHostValidationMiddleware.ts
Comment thread code/lib/core-server/src/utils/getHostValidationMiddleware.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
code/lib/core-server/src/utils/__tests__/server-channel.test.ts (1)

136-136: Fix stale test comment for clarity.

This case is invalid-origin, not wrong-token.

✏️ Suggested edit
-    // Simulate upgrade request with wrong token
+    // Simulate upgrade request with invalid origin
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/lib/core-server/src/utils/__tests__/server-channel.test.ts` at line 136,
Update the stale test comment in server-channel.test.ts: locate the comment "//
Simulate upgrade request with wrong token" in the test around the invalid-origin
case and change it to accurately reflect the scenario (e.g. "// Simulate upgrade
request with invalid origin" or "// Simulate upgrade request with wrong origin")
so the comment matches the test behavior in the invalid-origin case.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@code/lib/core-server/src/utils/__tests__/server-channel.test.ts`:
- Around line 11-15: The test creates a transport options object with a unsafe
cast ("as any") which hides type mismatches; replace the cast by typing the
object with the proper interface used by the ServerChannel constructor
(ServerChannelTransportOptions) or the constructor parameter type (e.g., use:
const options: ServerChannelTransportOptions = { localAddress: ...,
networkAddress: ..., token: ... }), import that type if necessary, and remove
the "as any" so TypeScript will validate the option shape in
server-channel.test.ts (look for the options variable and the
ServerChannel/ServerChannelTransportOptions symbol to locate the code to
change).

---

Nitpick comments:
In `@code/lib/core-server/src/utils/__tests__/server-channel.test.ts`:
- Line 136: Update the stale test comment in server-channel.test.ts: locate the
comment "// Simulate upgrade request with wrong token" in the test around the
invalid-origin case and change it to accurately reflect the scenario (e.g. "//
Simulate upgrade request with invalid origin" or "// Simulate upgrade request
with wrong origin") so the comment matches the test behavior in the
invalid-origin case.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 899964aa-179b-4f8d-8809-30dd7653fce2

📥 Commits

Reviewing files that changed from the base of the PR and between 1f3f0b0 and c233d2f.

📒 Files selected for processing (2)
  • code/jest.config.base.js
  • code/lib/core-server/src/utils/__tests__/server-channel.test.ts

Comment thread code/lib/core-server/src/utils/__tests__/server-channel.test.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
code/lib/core-server/src/utils/getHostValidationMiddleware.ts (2)

52-54: ⚠️ Potential issue | 🟡 Minor

Correct the Host-header note in the middleware docs.

Line 53 is inaccurate: normal browser HTTP/1.1+ requests (including address-bar navigation) generally include a Host header.

Suggested wording
- * Validates the Host header against known local/network addresses and allowed hosts. Requests with
- * no Host header (e.g. same-origin navigation, GET from address bar) are not allowed.
+ * Validates the Host header against known local/network addresses and allowed hosts.
+ * Missing Host headers are typically malformed/legacy client cases and are rejected.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/lib/core-server/src/utils/getHostValidationMiddleware.ts` around lines
52 - 54, Update the middleware comment in getHostValidationMiddleware to correct
the inaccurate note about Host headers: replace the sentence claiming "no Host
header (e.g. same-origin navigation, GET from address bar) are not allowed" with
wording that correctly states modern browser HTTP/1.1+ requests (including
address-bar navigations) generally include a Host header, and clarify that the
middleware rejects requests that are missing or malformed Host headers while
still allowing recognized local/network and allowed hosts; locate and edit the
comment block above the getHostValidationMiddleware function to make this
change.

36-40: ⚠️ Potential issue | 🟠 Major

Remove the implicit allow-all path for 0.0.0.0.

Line 38 currently disables host validation when bound to 0.0.0.0 and no explicit allowedHosts are set, which undermines this security hotfix in common container setups.

Suggested fix
-    // Setting host to 0.0.0.0 binds to all hosts, which implies allowing all hosts.
-    // This is common in containerized environments like Docker.
-    if (options.host === '0.0.0.0' && allowedHosts.length === 0) {
-      return true;
-    }
+    // Keep validation active even when binding to 0.0.0.0.
+    // Use `allowedHosts: true` only when intentionally opting into allow-all.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/lib/core-server/src/utils/getHostValidationMiddleware.ts` around lines
36 - 40, Remove the implicit allow-all branch that returns true when
options.host === '0.0.0.0' and allowedHosts.length === 0 so host validation
always runs; specifically, delete the if (options.host === '0.0.0.0' &&
allowedHosts.length === 0) { return true; } path in getHostValidationMiddleware
and ensure the middleware continues to validate requests against allowedHosts
(or fail when none are configured) so binding to 0.0.0.0 no longer bypasses
checks for host validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@code/lib/core-server/src/utils/getHostValidationMiddleware.ts`:
- Around line 52-54: Update the middleware comment in
getHostValidationMiddleware to correct the inaccurate note about Host headers:
replace the sentence claiming "no Host header (e.g. same-origin navigation, GET
from address bar) are not allowed" with wording that correctly states modern
browser HTTP/1.1+ requests (including address-bar navigations) generally include
a Host header, and clarify that the middleware rejects requests that are missing
or malformed Host headers while still allowing recognized local/network and
allowed hosts; locate and edit the comment block above the
getHostValidationMiddleware function to make this change.
- Around line 36-40: Remove the implicit allow-all branch that returns true when
options.host === '0.0.0.0' and allowedHosts.length === 0 so host validation
always runs; specifically, delete the if (options.host === '0.0.0.0' &&
allowedHosts.length === 0) { return true; } path in getHostValidationMiddleware
and ensure the middleware continues to validate requests against allowedHosts
(or fail when none are configured) so binding to 0.0.0.0 no longer bypasses
checks for host validation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9c2ddb64-63fd-4fd4-8c94-fa1e0f08f6b1

📥 Commits

Reviewing files that changed from the base of the PR and between c233d2f and a556935.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (5)
  • code/builders/builder-manager/src/utils/template.ts
  • code/lib/core-server/package.json
  • code/lib/core-server/src/dev-server.ts
  • code/lib/core-server/src/utils/getHostValidationMiddleware.ts
  • code/lib/core-server/src/utils/output-startup-information.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
CHANGELOG.md (2)

7-7: Fix typo in previous release notes.

There's a typo on line 7: "websocke" should be "websocket".

-- Harden websocke connection
+- Harden websocket connection

While this is pre-existing content and not part of the current changes, it would be good to fix it for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CHANGELOG.md` at line 7, Fix the typo in the changelog: replace the string
"websocke" with "websocket" in the CHANGELOG.md entry (the line containing
"Harden websocke connection") so the release note reads "Harden websocket
connection".

1-3: Consider adding more detail to the changelog entry.

The changelog entry is quite minimal compared to other entries in this file. Consider adding:

  • A reference to the source PR (e.g., "[#33835]")
  • A brief description of what request validation covers (host/origin validation for HTTP and WebSocket)
  • Contributor attribution if applicable

Example:

 ## 7.6.24
 
-- Add request validation
+- Core: Add host/origin validation for HTTP requests and WebSocket connections [`#33835`](https://github.com/storybookjs/storybook/pull/33835)

This would help users better understand the scope of the change.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CHANGELOG.md` around lines 1 - 3, Update the CHANGELOG.md entry under "##
7.6.24" to expand the minimal line "- Add request validation": include the PR
reference (e.g., "[`#33835`]"), a short summary that request validation covers
host/origin validation for both HTTP and WebSocket, and add contributor
attribution (e.g., "Contributed by `@username`") so the entry matches the detail
level of other changelog items.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@CHANGELOG.md`:
- Line 7: Fix the typo in the changelog: replace the string "websocke" with
"websocket" in the CHANGELOG.md entry (the line containing "Harden websocke
connection") so the release note reads "Harden websocket connection".
- Around line 1-3: Update the CHANGELOG.md entry under "## 7.6.24" to expand the
minimal line "- Add request validation": include the PR reference (e.g.,
"[`#33835`]"), a short summary that request validation covers host/origin
validation for both HTTP and WebSocket, and add contributor attribution (e.g.,
"Contributed by `@username`") so the entry matches the detail level of other
changelog items.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8bb5a9d9-b6a8-45c9-9c79-e90311e459e9

📥 Commits

Reviewing files that changed from the base of the PR and between 74e6c26 and 16bff83.

📒 Files selected for processing (1)
  • CHANGELOG.md

@ghengeveld ghengeveld requested a review from vanessayuenn as a code owner March 6, 2026 09:01
@ghengeveld ghengeveld merged commit add05b4 into v7 Mar 6, 2026
4 of 5 checks passed
@ghengeveld ghengeveld deleted the origin-validation-v7 branch March 6, 2026 10:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:daily Run the CI jobs that normally run in the daily job. maintenance User-facing maintenance tasks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant