Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This vulnerability is basically the worst-case version of what people have been warning about since RSC/server actions were introduced.

The server was deserializing untrusted input from the client directly into module+export name lookups, and then invoking whatever the client asked for (without verifying that metadata.name was an own property).

    return moduleExports[metadata.name]

We can patch hasOwnProperty and tighten the deserializer, but there is deeper issue. React never really acknowledged that it was building an RPC layer. If you look at actual RPC frameworks like gPRC or even old school SOAP, they all start with schemas, explicit service definitions and a bunch of tooling to prevent boundary confusion. React went the opposite way: the API surface is whatever your bundler can see, and the endpoint is whatever the client asks for.

My guess is this won't be the last time we see security fallout from that design choice. Not because React is sloppy, but because it’s trying to solve a problem category that traditionally requires explicitness, not magic.



To me it just looks like unacceptable carelessness, not an indictment of the alleged "lack of explicitness" versus something like gRPC. Explicit schemas aren't going to help you if you're so careless that, right at the last moment, you allow untrusted user input to reference anything whatsoever in the server's name space.


But once that particular design decision is made it is a question of time before that happens. The one enables the other.

The fact that React embodies an RPC scheme in disguise is quite obvious if you look at the kind of functionality that is implemented, some of that simply can not be done any other way. But then you should own that decision and add all of the safeguards that such a mechanism requires, you can't bolt those on after the fact.


this

I always felt server-action had too much "magic"


All mistakes can be blamed to "carelessness". This doesn't change the fact that some designs are more error-prone and more unsafe.


The endpoint is not whatever the client asks for. It's marked specifically as exposed to the user with "use server". Of course the people who designed this recognize that this is designing an RPC system.

A similar bug could be introduced in the implementation of other RPC systems too. It's not entirely specific to this design.

(I contribute to React but not really on RSC.)


”use server” is not required for this vulnerability to be exploitable.


wait I'm only using React for SPA (no server rendering)

am I also vulnerable??????


Only if you are running a vulnerable version of Next.js server.


No, unless you run the React Server Component runtime on your server, which you wouldn't do with a SPA, you would just serve a static bundle.


so any package could declare some modules as “use server” and they’d be callable, whether the RSC server owner wanted them to or not? That seems less than ideal.


The vulnerability exists in the transport mechanism in affected versions. Default installs without custom code are also vulnerable even if they do not use any server components / server functions.


They were warned. I don't see how this can be characterized as anything but sloppy.


You can call anything, anytime, anywhere without restrictions or protection.

Imagine these dozens of people, working at Meta.

They sit at the table, they agree to call eval() and not think "what could go wrong"


Eval has been known to be super dangerous since before the internet grew up and went mainstream. It is so dangerous that to deploy stuff containing it should come with a large flashing warning whenever you run it.


Half of web map solutions rely on workers, which can't be easily loaded from 3rd party origins, so are loaded as blobs. loading worker from blob is effectively an eval.


The client sort of exists to have code injected into it though?


If you want to describe text mark-up as programming, then yes. But most people do not do that.


hmm isn't eval is used in figurative-sense here eh?

maybe you should get some sleep


No, their whole point is that what they are doing is the literal equivalent of calling eval. Whether that actually uses the word 'eval' or a function called 'eval' is besides the point.


> The server was deserializing untrusted input from the client directly into

If I had a dollar for every time a serious vulnerability that started like this was discovered in the last 30 years...


For the layperson, does this mean this approach and everything that doesn't use it is not secure?

Building a private, out of date repo doesn't seem great either.


Not quite. This isn’t saying React or Next.js are fundamentally insecure in general.

The problem is this specific "call whatever server code the client asks" pattern. Traditional APIs with defined endpoints don’t have that issue.


I’m not asking if it’s fundamentally insecure.

Architecturally there appears to be an increasingly insecure attack surface appearing in JavaScript at large, based on the insecurities in mandatory dependencies.

If the foundation and dependencies of react has vulnerabilities, react will have security issues indirectly and directly.

This explicit issue seems to be a head scratcher. How could something so basic exist for so long?

Again I ask about react and next.js from their perspective or position of leadership in the JavaScript ecosystem. I don’t think this is a standard anyone wants.

Could there be code reviews created for LLMs to search for issues once discovered in code?


To be fair, the huge JavaScript attack surface has ALWAYS been there. JavaScript runs in a really dynamic environment and everything from XSS-onwards has been fundamentally due to why you can do with the environment.

If you remember “mashups” these were basically just using the fact that you can load any code from any remote server and run it alongside your code and code from other servers while sharing credentials between all of them. But hey it is very useful to let Stripe run their stripe.js on your domain. And AdSense. And Mixpanel. And while we are at it let’s let npm install 1000 packages for a single dependency project. It’s bad.


You mean call whatever server action the client asks? I don't think having this vulnerability was intentional.


This is only really fine as long as you have extremely clearly, well defined actions. You need to verify that the request is sane, well-formed, and makes sense for the current context, at the very least.


You would probably need to do the same if you were writing back-end in Go or something. I don't see how that is conceptually different.


As I understand it, RSC is locating the code to run by name, where the name is supplied by the client.

JS/Node can do this via import() or require().

C, C++, Go, etc can dynamically load plugins, and I would hope that people are careful when doing this when client-supplied data. There is a long history of vulnerabilities when dlopen and dlfcn are used unwisely, and Windows’s LoadLibrary has historical design errors that made it almost impossible to use safely.

Java finds code by name when deserializing objects, and Android has been pwned over and over as a result. Apple did the same thing in ObjC with similar results.

The moral is simple: NEVER use a language’s native module loader to load a module or call a function when the module name or function name comes from an untrusted source, regardless of how well you think you’ve sanitized it. ALWAYS use an explicit configuration that maps client inputs to code that it is permissible to load and call. The actual thing that is dynamically loaded should be a string literal or similar.

I have a boring Python server I’ve maintained for years. It routes requests to modules, and the core is an extremely boring map from route name to the module that gets loaded and the function that gets called.


I don’t think I’ve heard of intentional vulnerabilities?


Log4j almost seemed like it


Seems subjective and a personal interpretation.


I mean yeah


xz?


> We can patch hasOwnProperty and tighten the deserializer, but there is deeper issue. React never really acknowledged that it was building an RPC layer. If you look at actual RPC frameworks like gPRC or even old school SOAP, they all start with schemas, explicit service definitions and a bunch of tooling to prevent boundary confusion. React went the opposite way: the API surface is whatever your bundler can see, and the endpoint is whatever the client asks for.

> My guess is this won't be the last time we see security fallout from that design choice. Not because React is sloppy, but because it’s trying to solve a problem category that traditionally requires explicitness, not magic.

Now I'm worried, but I don't use React. So I will have to ask: how does SvelteKit fares in this aspect?


Indeed this is pretty bad.

The vast majority of developers do not update their frameworks to the latest version so this is something that will linger on for years. Particularly if you're on Next something-like-12 and there's breaking changes in order to go to 16 + patch.

OTOH this is great news for bad actors and pentesters.


This doesn't affect Next 12. Every single minor version of Next that's affected has a patch in the corresponding minor release cycle: https://nextjs.org/blog/CVE-2025-66478#fixed-versions


Just like the old days of PHP servers exposing their source code


How do hackers exploit it? Can I test it on my site?


> it’s trying to solve a problem category that traditionally requires explicitness, not magic.

i've been thinking basically this for so long, i'm kinda happy to be validated about this lol


while(true){

  console.log("jsjs")

}


Yghhhvv




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: