by makepanic on 3/22/25, 9:19 PM with 204 comments
by dminik on 3/23/25, 5:02 PM
For starters, there's no official way to chain multiple middlewares. If you want to do multiple things, you either stuff it all into a single function or you have to implement the chaining logic yourself. Worse, the main functions (next, redirect, rewrite, ...) are static members on an imported object. This means that if you use third party middlewares, they will just automatically do the wrong thing and break your chaining functionality.
Then, there's no good way to communicate between the middleware and the route handlers. Funnily enough the only working one was to stuff data through headers and then retrieve it through headers(). If someone knows your internal header names this could be very unsafe.
One additional issue with that is that headers() turns your route handler into a dynamic one. This opts you out of automatic caching. I think they recently gave up on this entirely, but this was the second biggest feature of Next 14 and you lost it because you needed data from the middleware ...
And lastly it still hides information from you. For whatever reason request.hostname is always localhost. Along with some other properties that you might need being obfuscated. If you really wanted to get the actual hostname you needed to grab it out of the "Host" header.
I'm not really surprised that the header/middleware system is insecure.
by ratorx on 3/22/25, 11:02 PM
https://zeropath.com/blog/nextjs-middleware-cve-2025-29927-a...
This looks trivially easy to bypass.
More generally, the entire concept of using middleware which communicates using the same mechanism that is also used for untrusted user input seems pretty wild to me. It divorces the place you need to write code for user request validation (as soon as the user request arrives) from the middleware itself.
Allowing ANY headers from the user except a whitelisted subset also seems like an accident waiting to happen. I think the mindset of ignoring unknown/invalid parts of a request as long as some of it is valid also plays a role.
The framework providing crutches for bad server design is also a consequence of this mindset - are there any concrete use cases where the flow for processing a request should not be a DAG? Allowing recursive requests across authentication boundaries seems like a problem waiting to happen as well.
by smlx on 3/23/25, 12:50 AM
I was made aware recently of a vulnerability that was fixed by this patch: https://github.com/vercel/next.js/pull/73482/files
In this vulnerability, adding a 'x-middleware-rewrite: https://www.example.com' header would cause the server to respond with the contents of example.com. i.e. the worlds dumbest SSRF.
Note that there is no CVE for this vulnerability, nor is there any clear information about which versions are affected.
Also note that according to the published support policy for nextjs only "stable" (15.2.x) and "canary" (15.3.x) receive patches. But for the vulnerability reported here they are releasing patches for 14.x and 13.x apparently?
https://github.com/vercel/next.js/blob/canary/contributing/r...
IMO you are playing with fire using nextjs for anything where you care about security and maintenance. Which seems insane for a project with 130k+ Github stars and supported by a major company like vercel.
by ronbenton on 3/23/25, 12:30 AM
2025-02-27T06:03Z: Disclosure to Next.js team via GitHub private vulnerability reporting
2025-03-14T17:13Z: Next.js team started triaging the report
by mikeocool on 3/23/25, 12:20 AM
React added a lot of complexity to the front end, but, for an app with a lot of front end state, brought a ton of value.
Next brings us file based routing, which seems cool, until you get into any sort of mildly complex use case, and — if your careful and don’t fuck it up, server side rendering, which I guess is cool, if you’re building an e-commerce product and is maybe cool for maybe a few other verticals?
by ronbenton on 3/22/25, 11:29 PM
The exploit involves crafting HTTP requests containing the malicious header:
GET /protected-route HTTP/1.1 Host: vulnerable-app.com x-middleware-subrequest: true
So... just adding a "x-middleware-subrequest: true" header bypasses auth? Am I understanding this correctly?
by makepanic on 3/22/25, 9:19 PM
by dvektor on 3/23/25, 12:29 AM
by urbandw311er on 3/22/25, 10:42 PM
The more comments I read about it in HN, the less comfortable I feel about this decision.
by ashishb on 3/22/25, 11:58 PM
The security posture for the code running in the browser is very different from the code running on a trusted backend.
A separation of concerns allows one to have two codebases, one frontend (untrustworthy but limited access) and one backend (trustworthy but a lot of access).
by ronbenton on 3/22/25, 11:26 PM
by foldr on 3/24/25, 11:11 AM
I’d rather just factor common logic into a function and call it in the handler for every route that needs it. Boring, repetitive - but easy to understand and debug.
It probably is a good idea to have some kind of thin middleware layer that adds an extra layer of auth protection, so that it’s more difficult to accidentally do something like allowing access to /api routes for users that aren’t logged in. But for reasons that are obvious in this context, you should never rely entirely on URL-based logic to protect access to resources.
by ramoz on 3/22/25, 11:47 PM
I hope Next's downfall sends a signal to the quality lib maintainers and changes direction (e.g. Remix and a f'd up router, TanStack w/ Start).
SSR frameworks make me vomit.
by impulser_ on 3/23/25, 5:23 AM
You just add a plugin into Vite and gain SSR, streaming, server functions, API routes with minimal configuration. You basically just add a ssr.tsx and client.tsx file into your existing TanStack Router application and it becomes full stack with full type safe.
If you want to go back to a React SPA just remove the plugin and config it back to SPA.
I built an app with it recently and it has an amazing DX.
Best part you can literally run it anywhere. It builds for any platform with a single configuration.
by butterlettuce on 3/22/25, 10:47 PM
by czk on 3/22/25, 10:47 PM
by prdonahue on 3/23/25, 12:13 AM
by rvz on 3/23/25, 12:31 AM
Add a single header 'x-middleware-subrequest' and it allows you to completely bypass any self-hosted Next.js middleware, including authorization.
This is beyond damning.
It's also exactly the reason why the whole Javascript ecosystem is really showing how immature it is and the hype and euphoria of Vercel is contributing to its clumsiness.
They are now also pushing "Vibe Coding", which is a hot air hype parade, about to be brutally hit with reality when others are deploying production code that is riddled with hundreds of security vulnerabilities.
A delightful golden age for professional security researchers.
by Lucasoato on 3/22/25, 10:48 PM
by ldjkfkdsjnv on 3/22/25, 10:38 PM
by yieldcrv on 3/24/25, 7:44 PM
I think this discussion is bringing a lot of unrelated angst out of the wood works that is beyond the level of rationality warranted
I think its rightful to be skeptical of Vercel’s incentives to vendor lock, and how long it took to deal with this vulnerability. Thats all independent of most of what I’m reading here
by tdhz77 on 3/22/25, 11:23 PM
by rglover on 3/23/25, 8:36 PM
It uses plain HTML, CSS, and JS for components (no React, Vue, Svelte, etc.—just simple components any skill-level can grok) in an easy-to-learn API and pairs that with a batteries-included Node.js back-end built on top of Express. The server automatically does old fashioned server-side rendering in routes (literally a callback function mapped to a URL pattern w/ req and res objects).
This is not "just another JS framework." I intentionally designed it to not behave like Next.js and other JS frameworks (I take "never trust the client" very, very seriously).
by greysteil on 3/23/25, 1:13 AM
* Reported to the maintainers privately
* Patch published and CVE issued before wider disclosure
* Automated fix PRs created within minutes of public disclosure (and for folks doing proactive updates, before)
The above is _really_ excellent. Compare that to Log4j, which no CVE and no patch at the time it became public knowledge, and it's clear we've come a long way.
Supply chain security isn't a solved problem - there's lots we can still improve, and not everything here was perfect. But hats off to @leerob and everyone else involved in handling a tough situation really well.