HomeVideos

I Tried to Warn You

Now Playing

I Tried to Warn You

Transcript

317 segments

0:00

Hey, remember this tweet from last

0:01

December when Next.js said, "Hey

0:03

everybody, you better upgrade. Uh if you

0:07

don't, well, there's kind of a remote

0:09

code execution on pretty much every

0:12

version of Next.js. So,

0:15

hey, but server components are really

0:16

cool though." And of course, everybody

0:18

upgraded only to be met yet again just a

0:20

couple days ago. Hey, guess what

0:22

everybody?

0:23

You better uh upgrade because well, if

0:27

you don't upgrade, you will simply have

0:30

um a denial of a middleware proxy

0:32

bypass, another a middleware proxy

0:34

bypass, another denial of service,

0:36

another middleware proxy bypass, a

0:38

server-side request forgery, a

0:39

middleware proxy bypass, a cross-site

0:42

scripting, a second cross-site

0:43

scripting, a denial of service, a cache

0:45

poisoning, a second cache poisoning, or

0:47

potentially a fifth middleware proxy

0:49

bypass.

0:51

Hey, you know what I'm talking about?

0:52

AI, man. Isn't AI pretty sweet? Like,

0:54

look at that. You know, like that's AI,

0:56

bro. That's what we're getting out of

0:58

this. Hey, honestly, React is more

1:00

secure now. You just got to upgrade.

1:02

Either way, I'd like to call myself a

1:04

bit of a Nostradamus.

1:06

As a person who's written a data

1:08

fetching library, let me just tell you,

1:10

it's really easy to screw it up. Now,

1:12

obviously, the forced upgrades will

1:14

continue until morale improves or you

1:17

finally switch over to using HTMX, which

1:20

by the way, the lord's library, and it

1:22

works really well with AI. So,

1:24

if you're I'm just just throwing that

1:26

out there, okay? Now, obviously, there's

1:28

quite a few vulnerabilities here, so we

1:30

are going to take apart the very tippy

1:32

top one, the highest one, which is

1:34

actually a bug that's within React. But

1:36

before we do that, we got to get the

1:37

bag. Hey, is that HTTP? Get that out of

1:41

here. That's not how we order coffee. We

1:43

order coffee via SSH, terminal.shop.

1:46

Yeah, you want a real experience? You

1:47

want real coffee? You want awesome

1:49

subscription so you never have to

1:51

remember again? Oh, you want exclusive

1:53

blends with exclusive coffee and

1:56

exclusive content? [music]

1:57

Then check out Chrome. You don't know

1:59

what SSH is?

2:01

Well, maybe the coffee's not for you.

2:04

>> [singing]

2:05

[music]

2:12

>> Now, there's no information on the

2:14

actual exploits, at least given out

2:16

publicly officially, but there is this

2:19

beautiful slop pository in which has

2:21

reproduction steps for pretty much every

2:24

single one of them all listed out

2:25

nicely. Now, we're going to go to the

2:28

very tippity top one that I showed you

2:29

before, and it gives you this beautiful

2:31

piece of code right here. And if you

2:32

jump into the YAML, you can actually

2:34

read what it's about. It's just taken

2:36

straight from the actual CV website,

2:38

which is going to say this: Next.js app

2:40

router consumes React decode reply

2:42

action bundled from React server DOM

2:44

webpack to parse React server components

2:47

replies server action bodies. Pre-patch

2:49

React walk the reply graph during model

2:51

resolution without any depth cycle or

2:54

row count limit. An unauthenticated

2:56

attacker can post a

3:00

form encoded reply body to an app router

3:02

page with the next action header and

3:05

force the server to spin CPU/stack

3:07

overflow for tens of seconds per

3:09

request. In other words, you're

3:11

effectively doing a DDoS. You're denying

3:13

the server's ability to process any

3:16

other request cuz remember, JavaScript.

3:19

Yo, we're single-threaded, pretty much.

3:21

As this thing just spins and does

3:22

nothing, your CPU's pegged and you have

3:24

pretty much no insights as to what's

3:26

happening, and you can even get a stack

3:28

overflow if you provide enough of these

3:31

encoded items. So, what are these

3:33

encoded items? Remember I said it was a

3:35

slop pository? Well, here's part of the

3:36

example of the slop pository. Inside of

3:39

this beautiful bash file, we also have

3:41

some beautiful Python going on right

3:43

here. I mean,

3:44

nothing tells me that an AI has written

3:47

something than code that looks like

3:48

this. This is This is what makes AI

3:51

happy, okay? If AI has the ability to be

3:54

in bash piping out to Python, I mean, it

3:57

is one happy mythos. Honestly, kind of

4:01

making Dario proud right now. And so,

4:02

then it produces this value right here

4:04

over and over again, and it does this

4:07

whole next thing right here. So, it

4:09

says, "Hey, all right. I'm going to

4:10

create a dollar sign F with a value in

4:14

hexadecimal, and I'm going to then going

4:16

to create an object that references this

4:18

next value also in hexadecimal. Now,

4:21

you're probably thinking, "Okay, I don't

4:22

even have any idea what that means."

4:25

Well, that's not a big deal, because

4:27

guess what? This isn't our first time

4:29

inside this code. So, if you go over to

4:31

this parse model string function, it

4:33

actually is doing the parsing. Now,

4:35

remember, in regular user land,

4:37

typically people from websites send up

4:39

JSON. Oh, no, no, no, no, no, no. Not in

4:43

React land. See, in React land, you have

4:45

your client, right? Big old C client

4:46

here. Let me increase the size. Oh,

4:48

and I went down in size. Oh my gosh,

4:51

embarrassing. Can I say that?

4:53

Embarrassing. Okay, a little too big,

4:55

but whatever.

4:56

Uh your client and your server

4:57

communicate back and forth. Now,

4:58

typically in your normal world, probably

5:00

at your normal job, you're using JSON.

5:03

So, you can just call like JSON.parse.

5:05

Better wrap a little try-catch around

5:06

that, or else your server explodes, but

5:08

you get the idea. Pretty

5:10

straightforward. Your client does the

5:11

exact same thing, but not in React

5:13

server components land. The special

5:15

meetings almost always start off as a

5:17

string. It starts off as a string with a

5:19

dollar sign. From there, it has some

5:20

sort of control character, like, "Hey,

5:22

what kind of action are you actually

5:24

asking me to perform?" If I remember

5:26

correctly, it's actually this code right

5:27

here, a subclass B for blob. This is

5:31

actually how the previous one had remote

5:33

code execution is by calling this

5:35

function right here, which ended up

5:36

returning a function in which was

5:38

actually specified as part of the input

5:40

and being stringified as a function into

5:42

an actual JavaScript function, which

5:44

allowed the user just to say, "Hey,

5:46

here's what I want you to execute. I

5:47

control the string and you turn it into

5:49

JavaScript for me and I can do whatever

5:51

I want on your machine."

5:53

It was not good, not good at all. But

5:55

this time, it's an uppercase F. Again,

5:57

jump right here, you can see the

5:59

uppercase F, so it's setting something

6:00

up. And what this does is this says,

6:02

"Hey, I have a reference. You are

6:05

referring to some object somewhere on

6:08

the server, so I'm going to decode it

6:10

for you." And so it does this get

6:12

outlined model call right here. Well,

6:14

outlined model will simply go off and do

6:17

the hydration, do whatever it needs to

6:19

do, except if this model has already

6:21

been resolved once before. Now, this is

6:23

where this beautiful loop comes in right

6:25

here because if you look at this, who am

6:27

I referring to? I'm going to refer to

6:29

the next one in line unless if we've

6:32

gone all the way around, then I'm going

6:33

to make a nice little ring right here,

6:35

so that way the last element refers to

6:37

the first element. So when we get here

6:39

and we've already initialized the model,

6:41

it's going to call this, "Hey, we need

6:42

to initialize this chunk." Specifically,

6:44

so it would actually points to the

6:45

correct object. Now, inside of

6:47

initialize model chunk, what it's doing

6:49

is going to revive the model. I assume

6:51

this is like the hydration process.

6:52

Like, "Hey, here's all the stuff that

6:53

exists on the server, so go off and do

6:55

it." Now, when you're reviving the

6:56

model, if the value I passed into you

6:59

was a string, oh my gosh, it's a string.

7:02

So it's going to go here and recall

7:04

parse model, so you can kind of guess

7:05

what happens here. We parse model to get

7:08

outlined model to initialize model chunk

7:10

to revive model to parse model string.

7:13

And we're just going to keep on doing

7:14

this nice little circle as much as we

7:16

can until bad things happen. In fact, it

7:19

only takes 53,000 times around this loop

7:21

for my stack to be exceeded. I bet your

7:23

servers probably are some cheap EC2

7:26

instances or something and they probably

7:27

don't get nearly as deep with the stack.

7:30

>> [snorts]

7:31

>> Now, the crazy part about this is that

7:33

the user doesn't even need to be

7:35

authenticated. They just simply need

7:37

access to this payload and you need to

7:38

be on an old enough version of React.

7:40

And so therefore, they can just send you

7:42

this message and boom your computer that

7:45

one single message one message means

7:48

your server up in the clouds completely

7:51

off. It's going to crash the process but

7:53

before it crashes the process it's going

7:55

to take hundreds of milliseconds if not

7:57

longer to process through everything

7:59

first. You see back in my day react used

8:02

to just be a view library. In fact way

8:05

way back in the day it used to say hey

8:08

we're the V in model view controller

8:11

MVC. Now I know those days are long

8:13

they're those are the bygone days of

8:15

yore at this point. Effectively react /

8:18

next JS just does everything. I I just

8:20

have a question okay? Honestly I don't

8:22

really understand the entire appeal of

8:25

server side components to begin with

8:26

right? Your client goes over here it

8:28

makes a request and all of this is to

8:31

prevent yourself from having the N plus

8:33

one query problem and you can also get

8:35

some kind of cool page dynamic caching

8:38

because the first moment you hit a

8:39

suspense like

8:42

component it oh my gosh look at that

8:44

line that was a perfect line. It once

8:46

you hit that first suspense whatever the

8:48

initial HTML that comes across the wire

8:50

that thing can be cached by a CDN and

8:53

then all the follow up stuff is only

8:54

user specific data. Like is that is that

8:56

the entire reason why people use react

8:58

server components? Am I crazy? This is a

9:01

lot of engineering just to avoid you

9:04

thinking about how to load your data.

9:06

I'm just going to throw it out there. I

9:07

feel like you you you could just you

9:09

could just do this instead. You know you

9:11

could just load the data you need. I

9:13

know novel concept. All right well looks

9:16

like that's it. I just kind of wanted to

9:17

yap about this for a little bit cuz I

9:19

thought these this was pretty

9:20

interesting. There's also one with cross

9:22

site scripting and how it does some you

9:24

know dangerously skip HTML which is very

9:27

funny by the way. It's super super funny

9:30

to see react the library in which you're

9:33

not supposed to have to think about HTML

9:35

and being able to do or like removing

9:38

any of the escaped characters or

9:40

anything like that. You don't have to

9:41

think about any of that. Instead, you

9:43

just hand it to React and it renders it

9:45

correctly and it just turns out you

9:47

can't hand everything to React because

9:49

some of the items underneath the hood,

9:51

well, they're actually using set HTML

9:53

dangerously and they weren't properly

9:55

escaping things. Very, very hilarious.

9:59

Anyways, so if hey, if you're using

10:01

React, you

10:03

better upgrade because even if you're

10:05

not using Next.js, you still got that

10:07

problem I just showed you right there.

10:08

That's pretty serious, huh? Can I tell

10:10

you Can I tell you like a little story

10:11

that I'm a little ashamed of? In 2016

10:14

when Netflix was flirting

10:17

with

10:18

with React and putting it on a

10:19

television, I was a part of the initial

10:21

performance side of things and when

10:24

comparing a very skinny app that has

10:27

virtually no features to an app that's

10:29

completely filled with features and has

10:30

a decade of legacy code, you may This

10:33

may surprise you, but the

10:35

the skinny one was faster. And so people

10:37

kept pushing it and I'm not going to lie

10:39

to you guys. During my dark days right

10:40

before I became jaded, but I thought

10:43

React was really great in 2016 and then

10:46

I used it a whole bunch and then I saw

10:48

what happened and then I I stopped

10:50

liking React after that.

10:51

>> [laughter]

10:52

>> I can't help it. I stopped liking it.

10:54

But you know what happened? I learned a

10:55

lot during those days, okay? I learned

10:57

very, very, very valuable lessons, which

11:00

was just say no early on. Just say no.

11:03

No.

11:05

A gen.

Interactive Summary

The video discusses recent, significant security vulnerabilities discovered in Next.js and React, highlighting a series of bugs ranging from denial of service to cross-site scripting. The speaker breaks down a specific vulnerability that allows an unauthenticated attacker to cause a stack overflow on the server through a specially crafted request, exploiting how React handles nested references. The video also explores the complexities introduced by React Server Components and shares the speaker's critical perspective on the evolution of React.

Suggested questions

2 ready-made prompts