TanStack Router XSS: How to Fix It
If your site runs TanStack Start, a critical, unauthenticated cross-site scripting bug could let an attacker run their own code in a visitor's browser just by getting them to click a link, and the fix is a one-line version bump.
This post is for anyone running a TanStack Start app built with React, Solid, or Vue on top of @tanstack/start-server-core, whether you wrote the code yourself or hired someone to build it. You will learn what the bug does, whether your site is on an affected version, and the exact steps to fix it today.
What is CVE-2026-102989?
TanStack Start is a full-stack framework for building apps on top of TanStack Router. It lets a React, Solid, or Vue app call server-side functions directly from the browser, kind of like calling an API without writing the API yourself.
On 2026-10-15, the GitHub Advisory Database published GHSA-qx66-fv34-fjm8, tracked as CVE-2026-102989, and rated it critical severity. The short version: an attacker who is not logged in can build a special URL pointing at one of your app's server functions. If a visitor opens that link, the app can send back attacker-controlled HTML from your own domain, and that HTML can run the attacker's JavaScript (the language browsers use to make pages interactive) right there in the visitor's browser.
This is a type of bug called reflected cross-site scripting, or XSS. "Reflected" means the malicious payload rides along in the link itself rather than being stored on your server; "cross-site scripting" means a third party's script ends up running on your site, in your visitor's session, with access to whatever that visitor's browser can see.
According to the advisory, the root cause sits in how the server-function transport (the code that moves data between browser and server function) handles request fields. Instead of only letting "public" input fields through, some fields can leak into internal middleware state. A malformed payload can then leave an attacker-controlled value sitting in the app's error-handling path, and the response handler can end up treating that value as if it were a legitimate HTTP response. Read the full technical writeup in GitHub's advisory for GHSA-qx66-fv34-fjm8.
Who is affected
This bug lives in the server-side transport layer, so it follows your @tanstack/start-server-core version and whichever framework wrapper you use on top of it.
| Package | Vulnerable versions | First patched version |
|---|---|---|
| @tanstack/start-server-core | >= 1.143.12, < 1.169.39 | 1.169.39 |
| @tanstack/react-start | >= 1.143.12, < 1.168.60 | 1.168.60 |
| @tanstack/solid-start | >= 1.143.12, < 1.168.57 | 1.168.57 |
| @tanstack/vue-start | >= 1.143.12, < 1.168.56 | 1.168.56 |
If your app pulls in any of these packages inside the listed ranges, you're affected, regardless of which frontend framework you used. You don't need every package above installed; you only need the one your stack actually uses, and start-server-core will always be present underneath it.
You are not affected if you're using plain TanStack Router without TanStack Start (no server functions), or if you're already on a version at or above the patched version for your framework.
How an attacker could actually use this
Because this flaw doesn't require a login, a session cookie, or any prior access, the attack pattern is simple:
- The attacker finds a server function exposed by your app (these are often visible in your app's JavaScript bundle or network requests).
- They craft a URL with a malicious payload aimed at that server function.
- They send that link to a target, for example in an email, a support ticket, or a chat message, exactly the way phishing links travel.
- The target, anyone with a browser, not necessarily an admin, clicks the link while viewing your site's origin.
- Your server returns attacker-controlled HTML, the browser runs it as if your own team wrote it, and the script now has the same access to the page that your own code has.
That last point is what makes XSS dangerous even without a direct data breach: a script running in your visitor's browser can access same-origin data available to that visitor (page content, some cookies, local storage) and make requests using their logged-in session. On an app with customer accounts, that can mean session hijacking or quiet account takeover; on a marketing or support surface, it can mean defaced content or redirect-based scams served from under your own domain name.
How to check if your site is affected
You don't need deep security tooling for this one; it's a dependency check.
- Open your project's package.json and search for @tanstack/start-server-core, @tanstack/react-start, @tanstack/solid-start, and @tanstack/vue-start.
- Run a version check instead of trusting package.json ranges, since a "^" or "~" range can resolve to an old installed version:
npm ls @tanstack/start-server-core @tanstack/react-start @tanstack/solid-start @tanstack/vue-start
- Compare each installed version against the "vulnerable versions" column in the table above.
- If you're on a platform like Vercel, Netlify, or a managed host, check the deployed build's lockfile (package-lock.json, pnpm-lock.yaml, or yarn.lock), not just your local machine, since those can drift apart.
- If an agency or contractor built the site, ask them directly which TanStack Start version is deployed; don't assume it was kept current after launch.
If you're not sure your site even uses TanStack Start, a developer can confirm it in under a minute by checking package.json. If nobody on your team can check this themselves, that's exactly the kind of gap a free passive website security check is built to catch.
How to fix it
The fix is a straightforward upgrade. There's no documented configuration workaround for this one, because the flaw sits in the transport code itself.
- Update to the first patched version for every TanStack Start package you use. For example:
npm install @tanstack/start-server-core@1.169.39 @tanstack/react-start@1.168.60
Swap in @tanstack/solid-start@1.168.57 or @tanstack/vue-start@1.168.56 depending on your framework.
- Or, more simply, update to the latest release of each package and let your package manager resolve to a current, patched version:
npm install @tanstack/start-server-core@latest @tanstack/react-start@latest
- Re-run your build and existing test suite before deploying. This is a server-transport fix, not a breaking API change, so most apps should see no behavior change beyond the patch.
- Deploy, then re-run the version check from the previous section against your live, deployed build, not just your local repo, to confirm the patched version actually shipped.
- If you maintain a CI pipeline, add a routine dependency audit (npm audit, or a scheduled Dependabot or Renovate check) so the next TanStack Start advisory doesn't sit unpatched for weeks.
If you can't patch today
If you can't upgrade immediately, maybe you're mid release-freeze, or the upgrade needs testing time, reduce exposure in the meantime:
- Put a web application firewall or reverse proxy in front of the app that can block unusually long or malformed query strings on server-function routes, as a stopgap, not a fix.
- Avoid emailing or publishing direct links to server-function endpoints.
- Move this patch above routine maintenance in your queue. A critical, unauthenticated, no-login-required XSS belongs at the top of the list, not in a "someday" backlog.
None of these replace the version upgrade. They only buy you time to do it properly.
Why "just a frontend bug" can still leak real data
Founders sometimes hear "XSS" and assume it's cosmetic, like a glitchy page. It isn't. A script running in a visitor's browser via your own domain can act with that visitor's authority: reading what they can read, clicking what they can click, submitting what they can submit. If you're running TanStack Start behind a customer login, a contact form, or a checkout flow, this is a data-exposure risk, not a display bug.
It's also a good moment to check the basics beyond this one advisory. A quick pass with a security headers checker will tell you whether protections like a Content-Security-Policy are in place, which can limit how much damage a future XSS bug, in TanStack or anywhere else in your stack, can actually do. And if you're weighing how deep a review you need, our guide comparing manual and automated penetration testing walks through when an automated scan is enough and when you want a person reviewing the actual code path.
Key takeaways
- CVE-2026-102989 is a critical, unauthenticated reflected XSS bug in TanStack Start's server-function response handling, published 2026-10-15 by the GitHub Advisory Database.
- It affects @tanstack/start-server-core (below 1.169.39), @tanstack/react-start (below 1.168.60), @tanstack/solid-start (below 1.168.57), and @tanstack/vue-start (below 1.168.56), for versions at or above 1.143.12.
- No login or special access is needed to exploit it; a visitor only has to click a crafted link.
- The fix is upgrading to the first patched version of whichever package you use, redeploying, and confirming the version against production, not a code rewrite.
- Set up ongoing dependency alerts (Dependabot, Renovate, or npm audit in CI) so you catch the next framework advisory before an attacker does.
What to do next
Patching this one advisory is a good afternoon's work for a developer. But if you're not sure what else is sitting unpatched, outdated, or misconfigured on your site, that's a different kind of question, and it's worth a second set of eyes. If you've already clicked a suspicious link or noticed odd behavior on your own site, our guide on what to do if your website was hacked covers the immediate steps. Otherwise, a real person manually reviewing your whole site for issues like this one, not just this one CVE, is what our $49 Circuit audit is for: one honest, human look at what's actually exposed, with exact fixes, no subscription to remember to cancel.
A real human security engineer audits your whole site by hand and sends a full report: every issue, its severity, and the exact fix. From $49, with a 14-day money-back guarantee.
See pricing