Guide · Frontend
Storybook's October 2026 Vulnerabilities Explained: Lock Down Your Dev Server
20 min readUpdated By Saket Bhatnagar
Researched and drafted with AI, reviewed and edited by Saket Bhatnagar.
In short
- The Storybook vulnerability of October 2026 is two bugs in storybook dev, the local server that shows your UI components while you code. Upgrade to 8.6.19, 9.1.21 or 10.6.2.
- The critical one (CVE-2026-114125): a website open in another tab could load the Storybook preview inside itself and send it messages. After a user interaction, that could change your story files.
- The high one (CVE-2026-114126): unfixed versions (we tested 10.6.1) listened on every network interface, and the pages carry a WebSocket token, a secret key for the live channel. Anyone on your Wi-Fi could read it.
- Code runs on your laptop only under extra conditions, and a built, static Storybook is not affected. By default, the fixed versions listen only on 127.0.0.1, your own machine.
- Beginners can stop after the section on when these bugs could run code, once they have upgraded. Engineers get version checks with expected output, a 10.6.1 vs 10.6.2 test, and two undocumented details: where the token still sits and what --host 0.0.0.0 reopens.
What goes wrong when a Storybook dev server trusts the wrong visitor?
A tool that runs only on your laptop can still take orders from strangers. That is the plain lesson of the Storybook vulnerability published in October 2026. Storybook's dev server can write files in your project, and before the fix it did not check carefully enough who was asking.
Storybook is a popular open-source tool for building UI components one at a time. You run storybook dev, open a browser tab, and click through buttons, forms and cards in isolation. Each example lives in a story file, a small JavaScript or TypeScript file next to your component.
Picture a common setup. A frontend developer in Pune works on a team's design-system repo at a co-working space. Storybook runs on port 6006 all day, while the same browser holds docs, chat and a few random links. The setup is made up, but both weaknesses are real and published.
Two things could go wrong for that developer. A web page in another tab could quietly load the Storybook preview inside itself and send it commands. Or someone else on the co-working Wi-Fi could open the dev server by IP address and get the key to its live channel. Both paths end at the same place: writes to story files on the laptop.
Which words do you need before reading the Storybook advisories?
Six terms carry the first half of the story. Each one is explained here once, and the rest of the guide uses the same names.
- Dev server: the program storybook dev starts. It serves web pages and listens for live updates while you code.
- Bind address: which network address a server listens on. 127.0.0.1 (also called localhost or loopback) means only this machine. 0.0.0.0 means every network card, so other devices can connect.
- LAN: local area network, the Wi-Fi or office network your laptop shares with nearby devices.
- Iframe: a page shown inside another page. Storybook's manager (the sidebar UI) shows each story in a preview iframe.
- postMessage: a browser feature that lets one window send a message to another, such as a page to its iframe. The receiver must check who sent it.
- WebSocket and token: a WebSocket is a connection that stays open so the browser and the dev server can push messages both ways. The token is a random secret in the page that your tab sends back to open it.
What is the Storybook vulnerability of October 2026?
The Storybook vulnerability is really two advisories that share one fix. Both let an outsider talk to a running storybook dev server and get it to write files in your project. They differ in who the outsider is and how they get in. CVSS, in the table below, is the standard 0 to 10 severity score.
| Detail | Website path (GHSA-f2ph-cmg5-wxc8) | Wi-Fi path (GHSA-px85-f4q5-jh77) |
|---|---|---|
| CVE ID | CVE-2026-114125 | CVE-2026-114126 (listed by OSV) |
| Severity | Critical, CVSS v4 9.4 | High, CVSS v4 8.7 |
| Who attacks | A website open in your browser | A device on the same network |
| Way in | Frames the preview page and sends it messages | Loads the dev server page by IP and reads the token |
| Needs from you | Dev server open in a browser, plus a user interaction | Dev server reachable on the network |
| Worst case | Changed story files; code runs only if a local runtime later executes one | Injected or new files; code runs only under the right circumstances |
| Not affected | Built Storybooks; dev servers never opened in a browser | Built Storybooks; trusted or closed networks, unless a fake hotspot poses as a trusted one |
Affected versions are storybook 8.0.0 up to 8.6.18, 9.0.0 up to 9.1.20 and 10.0.0 up to 10.6.1. The same ranges cover @storybook/core, @storybook/core-server and @storybook/experimental-addon-test on 8.x. They also cover @storybook/addon-vitest from 9.0.0, and @storybook/addon-mcp from 10.6.0.
How could a website you visit reach a server on your own laptop?
Your browser is the bridge. Any page you open can ask the browser to load http://localhost:6006 inside an iframe, because a page may embed other sites unless they refuse. The request comes from your own machine, so the dev server sees a normal local visitor.
The naive belief: localhost is private
Many developers think a server on localhost is safe because the internet cannot reach it. That belief is wrong for browsers. Every tab runs on your machine, so every site you visit sits on the right side of that wall.
Storybook 10.6.1 already had one defence. It checks the Host header, the name the browser says it is visiting. That blocks DNS rebinding, a trick where an attacker's domain is re-pointed at 127.0.0.1 so the browser treats your server as the attacker's site.
The answer is framing. When a page embeds http://localhost:6006/iframe.html, the browser sends Host: localhost, which passes the check. The attacking page then calls postMessage on that iframe. In 10.6.1, the preview did not check the origin of those messages in dev mode. The origin is the scheme, host and port of the page that sent them.
The advisory's timeline says a reporter showed on 30 September that a malicious site could embed a dev server's preview iframe and send it events. The advisory does not publish every later step. One part of the fix points at the last step: the server now ignores save requests unless they come from the manager's own connection.
The website path to an older dev server (GHSA-f2ph-cmg5-wxc8)
Drag to exploreNotice that every hop happens inside your own browser or laptop, so the Host check passes. The advisory does not publish every step; this is the path the fix closes.
Diagram connections:
- Malicious web page to Preview iframe (embeds)
- Preview iframe to postMessage events (receives)
- postMessage events to WebSocket channel (reach server, steps unpublished)
- WebSocket channel to Story files (writes)
- Story files to Local runtime runs file (extra condition)
- Malicious web page: Tab → embeds localhost:6006
- Preview iframe: Browser → loads Storybook preview
- postMessage events: Malicious page → preview, no origin check
- WebSocket channel: Dev server channel; exact steps unpublished
- Story files: Dev server → project folder
- Local runtime runs file: Only if something later executes it
The advisory also says recent Chrome and Firefox versions may ask before a website connects to a localhost service. In its words, that reduces the risk but does not remove it. Do not rely on a browser prompt as your only lock.
How did the WebSocket token leak to anyone on the same Wi-Fi?
The token was never hidden from people who could load the page. Storybook writes it into the manager page and the preview page so your tab can open the WebSocket. Unfixed versions also listened on every network interface by default in our 10.6.1 test. So anyone on the co-working Wi-Fi from our setup could load that page by IP address.
We tested this on our own machine. Storybook 10.6.1, started with plain storybook dev and no --host flag, listened on 0.0.0.0:6006. Its startup banner even printed an On your network address. Version 10.6.2 listened on 127.0.0.1:6006 only.
Why 0.0.0.0? Storybook 10.6.1 passed no host to Node's listen call. Node's documentation says that with no host, a server accepts connections on :: when IPv6 is available, or 0.0.0.0 otherwise. Both mean every interface.
With the token, a device on the LAN can open the same WebSocket your browser uses. The advisory says that channel could inject code into story files or create new files. If the Vitest addon is installed, a payload could also use a Vitest API to write other files. The advisory says the risk is higher with an older Vitest version.
The LAN path to an older dev server (GHSA-px85-f4q5-jh77)
Drag to exploreThe token works as a lock only when the page holding it is unreachable. Binding to 0.0.0.0 is the step that broke that assumption.
Diagram connections:
- Device on same Wi-Fi to Dev server on 0.0.0.0 (connects by IP)
- Dev server on 0.0.0.0 to Manager page (serves)
- Manager page to WebSocket with token (token reused)
- WebSocket with token to Story files changed (save requests)
- Story files changed to Vitest browser API (test run, if present)
- Dev server on 0.0.0.0: Laptop → listens on every interface
- Device on same Wi-Fi: LAN device → http://LAPTOP-IP:6006
- Manager page: Dev server → LAN device, token inside
- WebSocket with token: LAN device → dev server channel
- Story files changed: Dev server → project folder
- Vitest browser API: If addon installed: more file writes
When could these Storybook bugs lead to running code on your machine?
Only when extra conditions line up. Both advisories describe file writes as the direct result. Code execution needs a second step: something on your machine later runs a changed or new file with your user's rights.
For the website path, the advisory says it needs user interaction and a later local runtime run. For the LAN path, it says code can run under the right circumstances, depending on the payload, where the file lands and what software you use. Neither advisory claims a one-click takeover.
Two groups are clearly outside the blast radius. A built, static Storybook, the output of storybook build, has no write channel and no token. A dev server never opened in a browser, such as one driven by headless automation, is outside the website path.
Beginners can stop here, after one step. Upgrade Storybook to 8.6.19, 9.1.21 or 10.6.2, then run npx storybook --version to confirm. The rest of this guide is for engineers: what the fix changed, how to test your setup and what still needs care.
What changed in Storybook 8.6.19, 9.1.21 and 10.6.2?
The fix closes both doors and narrows what the channel will accept. One new term first: frame-ancestors is a rule, sent in a Content-Security-Policy response header, that tells browsers which sites may embed a page. We installed storybook 10.6.1 and 10.6.2 from npm and compared their behaviour and source. We read the 8.6.19 and 9.1.21 packages to confirm the same default.
| Behaviour | 10.6.1 | 10.6.2 | How we checked |
|---|---|---|---|
| Listen address with no --host | 0.0.0.0:6006 (all interfaces) | 127.0.0.1:6006 only | Started both, read the listening sockets |
| Startup banner, network line | Prints a LAN address | Says to run with --host and your IP | Read the console output |
| Embedding by other sites | No frame-ancestors header | frame-ancestors allows self and localhost only | curl -sI on the page |
| postMessage in dev mode | No origin check | Own origin and localhost names only | Read channels source |
| Host header other-site.example | 403 Forbidden | 403 Forbidden | curl with that Host header |
| Token inside manager and preview pages | Yes | Yes | curl over 127.0.0.1, value redacted |
| Vitest browser write and exec | Left as configured | Forced off unless you set them | Read addon-vitest source |
The four main changes
- Default bind address: 127.0.0.1. To share on a LAN, pass --host with your LAN IP. The advisory also asks you to list that IP in core.allowedHosts and allow only known IPs in a firewall.
- Framing: a Content-Security-Policy header with frame-ancestors 'self' plus localhost names tells browsers to refuse embedding by other sites. The flag security.insecureRemoteIframeEmbed turns it off.
- Messages: in dev mode the preview drops postMessage events from unknown origins. The flag security.insecureIframeMessaging turns the check off; built Storybooks still accept any origin.
- Vitest addon: when browser mode is on, the addon sets allowWrite and allowExec to false unless your Vitest config sets them.
Smaller changes back these up. The server now tags each WebSocket client as manager, preview or server, and ignores core events from the wrong one. Save requests may write only serialized args and story titles, so a request can no longer smuggle in a play function.
Two breaking changes are the most likely to touch your setup. The highlight event changed its signature with no flag to restore it, and the advisory says Chromatic's Visual Tests addon needs 5.5.1 or later. Composition that embeds a dev server from another host may need the flags above; the advisory suggests composing built Storybooks instead.
How do you check your Storybook version and bind address?
Five quick checks give clear output. Run them inside the project that has Storybook installed.
Check the installed version
Run npx storybook --version. Our 10.6.1 project printed 10.6.1. Any version from 8.6.19, 9.1.21 or 10.6.2 upward on the same major line is fixed.
Find every copy in the tree
Run npm ls storybook. Addons pull storybook in too, so every line should show the same fixed version. Repeat for @storybook/addon-vitest if you use it.
Start Storybook and look at the banner
On a fixed version, the Local line shows http://127.0.0.1:6006/. The network line tells you to run with --host and your IP instead of printing an address.
Read the bind address
While it runs, use lsof, a tool that lists open files and network sockets, as below. 127.0.0.1:6006 means only your machine can connect. An asterisk before :6006 means every interface is listening. On Windows, or without lsof, the banner from step 3 is the simplest check.
Confirm the framing header
Run the curl command below. A fixed version prints a Content-Security-Policy line with frame-ancestors. An old version prints nothing.
npx storybook --version
npm ls storybook
# while storybook dev runs on port 6006 (macOS and Linux)
lsof -nP -iTCP:6006 -sTCP:LISTEN
curl -sI http://127.0.0.1:6006/ | grep -i content-security-policyWhat just happened? The lsof line shows who can connect, and the curl line shows whether other sites may embed the page. Here is what we saw on Linux, 25 October 2026; we did not test macOS. On 10.6.1, the last columns of the lsof line read TCP *:6006 (LISTEN), and curl printed nothing. On 10.6.2, they read TCP 127.0.0.1:6006 (LISTEN), and curl printed the frame-ancestors line.
# 10.6.2 output (lsof line trimmed to its first and last columns)
node TCP 127.0.0.1:6006 (LISTEN)
Content-Security-Policy: frame-ancestors 'self' http://localhost:* http://*.localhost:* http://127.0.0.1:*What should you do now if you use Storybook?
Upgrade first, then look for the settings that reopen the doors. The advisories ask you to upgrade before you run storybook dev again, and not to run an affected dev server until you can.
Upgrade every Storybook package together
Move to 8.6.19, 9.1.21 or 10.6.2, or later on your line. Keep framework packages and addons such as addon-vitest on the same version, then commit the lockfile.
Search scripts for --host
Look in package.json, Docker files and docs for --host 0.0.0.0 or -h 0.0.0.0. Remove it unless you truly need LAN access.
Share on a LAN the narrow way
If a teammate must open your Storybook, pass --host with your LAN IP, list it in core.allowedHosts and allow only known IPs in your firewall. Never do this on public Wi-Fi.
Leave the new flags off
Do not set security.insecureRemoteIframeEmbed, security.insecureIframeMessaging or core.allowedHosts true unless you can name the exact reason. For composition, the advisory suggests building composed Storybooks instead.
Re-enable Vitest write and exec only on purpose
If your browser-mode tests really write files or run commands, set allowWrite or allowExec yourself in the Vitest config, and know that you have widened the channel.
Look back at story files
If you ran an old version on shared Wi-Fi, review recent git changes in story files and new files you did not create. This is a precaution, not a sign that you were attacked.
Why is a local dev server part of your attack surface?
Your attack surface is every place an attacker could reach your systems. A local dev server belongs on that list: it is a web server with write access to your source code, and your browser visits untrusted pages all day. Any tool with both traits has this exposure in principle. These advisories show five defences in one place.
- Bind narrowly: listen on 127.0.0.1 by default and make LAN exposure a deliberate flag, ideally with a named IP.
- Check Host on every HTTP request: this stops DNS rebinding. Storybook 10.6.1 had it and was still exposed, which shows one check is not enough.
- Refuse framing: frame-ancestors stops other sites embedding your pages, so they cannot drive them with postMessage.
- Check the origin of every message: a postMessage listener that skips this check obeys any window that can reach it.
- Treat page-embedded tokens as weak: a secret printed into HTML protects only as far as the page is unreachable.
The deeper lesson is layered failure. Each gap alone was small: a wide bind address, a missing frame rule, an unchecked message, loose save validation. Together they formed a path from a web page or a Wi-Fi neighbour to your project folder.
How do you explain the Storybook vulnerability in a system design interview?
Use it as a case study in trust boundaries for developer tools. Interviewers want to hear who can reach the server, what it can do, and which layer should have stopped each step.
Name the asset
The dev server can write files in the project and trigger test runs. That makes it worth attacking even though it is only on a laptop.
List who can reach it
The local browser and every tab in it, plus the whole LAN when it binds to 0.0.0.0. Each is a different attacker with different abilities.
Walk one path end to end
A web page frames the preview and sends postMessage events. Those events reach the dev server, which writes a story file.
Put a control on each hop
Loopback bind for the LAN, frame-ancestors for embedding, origin checks for messages, sender roles for WebSocket events, strict validation for file writes.
Scope the impact honestly
File writes are direct; code runs only if a local runtime later executes the file. Built static output is not affected.
Questions people ask
- Is my deployed Storybook site affected by the October 2026 advisories?
- No, not if it is a built, static Storybook. The output of storybook build has no write channel to your project and no WebSocket token. Both advisories are about storybook dev, the local development server. Upgrade anyway so the next time someone runs storybook dev in that repo, it is safe.
- Do I need to rotate any secrets after upgrading Storybook?
- Not the Storybook token itself. Storybook makes a new random token each time storybook dev starts, so an old copy stops working after a restart. If you ran an old version on untrusted Wi-Fi, review recent story file changes and new files. Rotate other secrets only if you find changes you did not make.
- Does Storybook 10.6.2 still work with my teammate opening it from another laptop?
- Yes, but you must opt in. Start it with --host and your LAN IP; in our 10.6.2 test that alone worked, and foreign Host names still got 403. The advisory also asks you to list the IP in core.allowedHosts and allow only known colleague IPs in a firewall. It says to avoid --host on an untrusted Wi-Fi network.
- Why does Storybook say it is critical if code execution needs extra conditions?
- Because the score covers the worst case. The critical advisory's CVSS v4 vector rates confidentiality, integrity and availability impact as high for the affected system and later systems. The text still says code runs only if a changed file is later executed by a local runtime. Read both the score and the conditions.
- Can a browser prompt for local network access protect me instead of upgrading?
- Not fully. The advisory says recent Chrome and Firefox versions may prompt before a website connects to a localhost service, which reduces the risk but does not remove it. A prompt also does nothing for the LAN path, where another device talks to your dev server directly. Upgrading closes both.
- I use the Vitest addon. Do my browser tests break after upgrading?
- Only if they write files or run commands from browser mode. From 10.6.2 and 9.1.21, the addon sets allowWrite and allowExec to false unless your Vitest config sets them. If a test needs them, set them on purpose in your Vitest config and keep the dev server on 127.0.0.1.
- Does Storybook 11 have the same fix?
- Yes, for the alpha line. The advisories list 11.0.0-alpha.0 up to 11.0.0-alpha.5 as affected and 11.0.0-alpha.6 as fixed, as of 25 October 2026. Alpha versions change quickly, so check the latest release notes before you rely on any default there.
Sources and further reading
- GitHub Advisory Database: GHSA-f2ph-cmg5-wxc8, missing origin validation in Storybook preview (CVE-2026-114125)
- Storybook security advisory GHSA-px85-f4q5-jh77: dev server vulnerable to code injection from the local network
- OSV record for GHSA-px85-f4q5-jh77 (CVE-2026-114126 alias, affected ranges)
- Storybook pull request 36726: patch for both advisories
- Storybook fix commit 243c06b (merge of PR 36726, v11 patch)
- Storybook v10.6.2 release notes
- Storybook docs: main config core, allowedHosts
- Storybook docs: CLI options, dev --host
- Node.js docs: net server.listen default host