solid-v2/fullstack, fullstack-tanstack: server.js rejects the [...404] route chunk; check path containment instead of ".." - #305
Open
brenelz wants to merge 1 commit into
Conversation
…tring guard with resolved-path containment
server.js guarded static asset serving with `!url.includes('..')`. A
catch-all route `src/routes/[...404].tsx` builds to the client chunk
`dist/client/assets/_...404_-<hash>.js`, whose URL contains `..`, so the
request fell through to the SSR handler, which answered with the 404
page's HTML instead of JavaScript. The module preload failed and the 404
page never hydrated under `node server.js` (`vite preview` was
unaffected). Reproduced with solid-js 2.0.0-rc.6, @solidjs/router
2.0.0-next.21, @solidjs/vite-plugin 3.0.0-next.38:
`curl -i /assets/_...404_-<hash>.js` -> HTTP 404 text/html.
The guard now maps the decoded pathname onto dist/client with path.join
and serves only when the resolved path stays under that directory.
Everything else — `..`, `%2e%2e`, `..%2f`, malformed percent-encoding —
falls through to handleRequest as before. Side effect: the MIME type is
taken from the resolved file rather than the raw URL, so
`/assets/x.js?v=1` is application/javascript instead of octet-stream.
Both server.js copies stay identical. fullstack-tanstack has no
catch-all route file but shares the guard.
Verified in both templates: vitest suites green (10 each), `vite build`
clean, prod servers boot. fullstack: the `_...404_` chunk is served as
application/javascript, /some-missing-page preloads it, and the 404 page
hydrates (client-side navigation to / keeps window state; Counter
increments). Traversal probes get the SSR 404 page, never file contents.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
server.jsin both fullstack templates guards static asset serving with!url.includes('..'). A catch-all routesrc/routes/[...404].tsxbuilds todist/client/assets/_...404_-<hash>.js(Vite's chunk-name sanitizing turns the brackets into_and keeps the dots), so the chunk's URL contains.., the request falls through tohandleRequest, and the SSR handler answers a request for JavaScript with the 404 page's HTML. The module preload fails and the 404 page hydrates dead undernode server.js.vite previewis unaffected.Reproduced 2026-09-10 with solid-js 2.0.0-rc.6, @solidjs/router 2.0.0-next.21, @solidjs/vite-plugin 3.0.0-next.38 (
vite build, thenpnpm start):GET /assets/_...404_-DdAS84x5.js404 text/html200 application/javascriptGET /assets/index-CbEfGLRp.js?v=1200 application/octet-stream200 application/javascriptGET /../server/server.js,/%2e%2e/%2e%2e/package.json,/assets/..%2f..%2f..%2fpackage.json,/%,/assets/%00.jsThe fix maps the decoded pathname onto
dist/clientwithpath.joinand serves only when the resolved path starts with<clientDir>/; misses still fall through tohandleRequest. The MIME type now comes from the resolved file instead of the raw URL, which is what fixed the query-string row. Bothserver.jscopies stay byte-identical (fullstack-tanstackhas no catch-all route file, but it shares the guard). No README text describes the guard, so no docs change.Verified in both templates:
vitest rungreen (10 each),vite buildclean, prod servers boot. In a browser against the fullstack prod server,/some-missing-pagepreloads the_...404_chunk (200) and the 404 page hydrates: clicking Home is a client-side navigation (awindowmarker set on the 404 page survives it) and the Counter increments.Fragility note: the
..in the chunk name comes from Vite's default chunk-name sanitizing of the route file name[...404].tsx(brackets →_, dots kept) in the build @solidjs/vite-plugin drives (Vite 8 / rolldown). Any static host, CDN rule, or hand-written server with a "reject..in the path" guard refuses that chunk the same way. A sanitizer that also collapsed runs of dots would remove the whole class of problem upstream; that is probably worth an issue on the plugin or Vite, not attempted here.🤖 Generated with Claude Code