I’ve always placed this in mind. When a new solution is introduced to solve problem(s), somehow, it introduces a new problem or vulnerability while stopping one. That’s nature for me 😅
I'm glad someone finally took the time to actually run the tweeted code to understand it, besides only stating "I don't fully understand what's going on here..."! Thank you. I believe the risk is not really on using alpha features. I believe that the bigger risk is using sample code from someone else without putting the effort to actually understand it. Good job!
The risk is not understanding how any of this works and you accidentally leak your db secrets and your company’s reputation is ruined because everyone’s data is leaked
The actions are currently in Alpha so their security will be improved in the future. Currently, using it in production is not only shooting yourself in the foot, but blowing the entire leg off. And I do think that separating the actions in a different file is better anyway. Helps with security + separation of concerns.
Well before react, styles, markup and js logic was 3 different files (separation of concerns). JSX components meant you do all of the 3 together, and separate concerns on the component level.
I'm really not a fan of this direction in the first place. Next is trying so hard to blur the lines of the client and server paradigms that they are obfuscating the actual inner workings of the framework. This is going to make security vulnerabilities easier to create by accident and harder to spot :(
They are trying to pull everything under their umbrella: CSS, fonts, API, animation... everything, so you couldn't even think of getting rid of NextJS. And at some point, I imagine, NextJS will become Vercel-only. So every web developer would pay them. Sounds like a nice plan.
the secret is in the client side of course it's no surprise that you can see it in your browser. Just keep it in the server side. It's pretty simple to prevent this security issue.
it's really simple: every server action call is a separate http request that doesn't have access to any state of the server (assuming you are running serverless/edge, and it probably treats it independently even if you have a dedicated machine). Anything involved in a closure is treated like an argument. imo, it's better to explicitly pass them as arguments instead of hiding it behind a closure.
From what i get, is that you are right. No one should place it within the component and the right thing to do is to put it directly in the server function as he showed in the end of the video. The purpose of this video is just to warn people that if you put it inside the compoent function things can be leaked. This is just a video to prevent a flaw that have been fund on this alpha.
@@MrBrandenS why should this be fixed. There are lots of ways to leak your keys. Why should this be treated any differently? Anyone making this mistake is probably not working on a serious app anyway.
@@avi7278 elitism much? This is a simple mistake that could cause leaking a variable you think should only live on the server but is sent to the client. It’s much harder to make this mistake with a rest api because the api only returns what your explicitly specify as a return value. Next is exposing variables you never explicitly expose
This is basically the equivalent of doing const secret = fetch(/my/secret) in your react and that result gets bundled with the frontend. Closures are important in js for this and many other reasons.
when you define your screts inside the function they don't appear inside the payload if that means they are not sent to the client why wouldn't you define the secrets inside server actions ?
If you are building a long-term project, PLEASE go with an Express RESTful API + React SPA (Vite swc) + Zustand + React-Query. This stack is tried and true and will not screw you over. Don't chase the fancy new thing. Go for stability and reliability!
1:30 curios how you toggle between screens here without showing the app switcher. Are you doing that with a specific program or utility or is that being done some how with OBS?
it's state that is serialized. basically the Home component is async, so it loads up on the server and renders some html. The secret is loaded too, but that secret is basically some state of your component that, because it's declared and assigned there, next will assume it will be needed in the rendering process and possibly in the client as well, so it's probably stored as a json string somewhere in the serialized response (i'd suggest always checking the actual rendered html in the browser to make sure you're not leaking anything)
@@arpadgabor oo I see, didn't notice the async... Mm yes this does seem a bit error prone. But as the secret is in the serialized state in the first exampe, wouldn't that mean the secret is also visible there? It's not encrypted or anything right?
interesting, aside from any issues that come from using server actions in alpha, what will t3 stack look like? will trpc even be needed once server actions become the norm? atleast not for mutations of any kind 🤔
Just a note. Those aren’t the stable server components. They are server actions running inside client components and it’s in alpha still. If that becomes stable it would be cool.
Imo all of these alpha and beta features seriously need to be removed from the main release package and instead be added to packages named ”13.4.0-beta-{major}.{minor}" or something so that people aren't using these features in production unless the package version explicitly states that it's the beta/alpha version. Having these in the main package seems really weird to me.
I do agree, if it’s alpha do not put in the main release. In their defense you can not uses these features unless you set a flag to true in the next config, so it’s fine imo
Am I the only one who thinks that we don't need 'server actions'? Like seriously, what's wrong good ole JSON? I get that you can't really upload files with JSON, but with Next those files aren't persisted anyways... Plus, we figured this out with the whole pre-signed URLs thing.
I just can't see why someone would connect to a DB or do complex stuff with this server actions thing. We are already seeing some bad things about serverless, why should we go deeper?
You are fetching the secret inside your Home component, which means that code is being run on both the server AND the client. This being called a security vulnerability is just a failure to understand how Next executes your component code. Which don’t get me wrong, is perfectly valid criticism of Next but has nothing to do with Server Actions.
@@Reohh the component is a server rendered component, the secret does not get sent to the frontend at all. The server component is built to run the jsx on the backend so it only sends the html. The hydration part only happens with client components
@@WebDevCody put it this way: if your `getSecret` was implemented as `return Math.random()` and you called `getSecret` at the time the server component was served, even if the server action is only being executed on the server, the only way for your server action to be guaranteed to have the same "secret" you randomly generated at serve-time is by having your server component communicate the secret to the browser and the browser to the server action. you can't expect the closure's state (ie the `const secret`) to be preserved across both the synchronously served server component and the asynchronously executed server action *_unless_* you allow the browser, being the intermediary between the serving of the server component and executing of the server action, to preserve that state for you (eg what if you have a distributed architecture where the server component is served in the US but when the user calls the server action, they're in Europe?) the fix for this is to not allow secrets to cross "runtime" boundaries. we have several different runtime contexts: server (at server component serve-time), browser, and server action (at server-action execution time). when you try to create a secret (or any value for that matter) in one context but access it in another, that secret necessarily must be exposed, at least to the network communications. when I think about it this way, the answer to this is clearly to keep the "const secret = await getSecret" _inside_ the server action
This is a foot gun, but its not at all surprising or counterintuitive. If you remove the server action it's so obvious you are pulling a secret into a component! Why would you expect that secret to ever be excluded from client code if you did this? I guess the point is that you wouldn't do it on purpose, but it would be a careless mistake.
Idk if you fetch the secret in the server component, it won’t be sent to the frontend from what I can tell. The fact that you define the server action as an inner function causes it to be exposed. That’s not intuitive
@@WebDevCody oooooooooooooooooooooh Im dead wrong. I thought this was a client component. Yup you're 100% right this is super unintuitive and dangerous.
I'm not even against server action as a concept but wtf with that stupid hack of an API is "use server"? Like someone at facebook get paid to come up with that shit?
@@WebDevCody that's their model. It is an opt-in feature that you can enable at any time, in any project to experiment it. No need to switch branches or all that fancy stuff, just change the next config and you can experiment every testing feature
@@WebDevCody of course! My comment was not directed at you in any way, as you were only helping. It was directed to some people that is hating on Vercel for quite some time and using this as an argument to trash talk about them
Angular is the matured professional framework, it has simple syntax than react. React is hard to understand, the DX of react is horrible. React is a child play. When it comes to serious enterprise app development, Angular comes in glory. React has brought shame to JavaScript community by making web development unnecessarily complicated.
Everyone, just ignore this person. I have seen this exact account under many React videos. Don't listen to him, he is not here to make the web better, he is only here to trash on libraries/frameworks like React & Svelte and blame them for the web being bad.
I’ll retest but I didn’t find the secret in any of the frontend html or JavaScript when I did that approach, because react will run through your component once and evaluate everything and not send it to the server. It’s the same reason why we can do prisma or sql queries inside the server render component and not have it leak secrets.
@@WebDevCody it is leaking. You’re not using the variable in the function - hence it is not included in the rendered form. If you ‘console.log(secret)’ inside ‘doSomething’ (1:24) you will see that it leaks. This has nothing to do with sql or prisma, it’s to do with closures.
I’ve always placed this in mind. When a new solution is introduced to solve problem(s), somehow, it introduces a new problem or vulnerability while stopping one. That’s nature for me 😅
This is another reason why a strong split between front and backend code is useful
Keep ‘em coming Cody! You’re doing so well! I’m very proud of you 😘
Thank you beautiful! 😘
I'm glad someone finally took the time to actually run the tweeted code to understand it, besides only stating "I don't fully understand what's going on here..."! Thank you. I believe the risk is not really on using alpha features. I believe that the bigger risk is using sample code from someone else without putting the effort to actually understand it. Good job!
The risk is not understanding how any of this works and you accidentally leak your db secrets and your company’s reputation is ruined because everyone’s data is leaked
@@WebDevCody exactly. And this can happen with the most stable features if the developer does not put the effort in understanding them.
The actions are currently in Alpha so their security will be improved in the future.
Currently, using it in production is not only shooting yourself in the foot, but blowing the entire leg off.
And I do think that separating the actions in a different file is better anyway. Helps with security + separation of concerns.
Well before react, styles, markup and js logic was 3 different files (separation of concerns). JSX components meant you do all of the 3 together, and separate concerns on the component level.
I'm really not a fan of this direction in the first place. Next is trying so hard to blur the lines of the client and server paradigms that they are obfuscating the actual inner workings of the framework. This is going to make security vulnerabilities easier to create by accident and harder to spot :(
They are trying to pull everything under their umbrella: CSS, fonts, API, animation... everything, so you couldn't even think of getting rid of NextJS. And at some point, I imagine, NextJS will become Vercel-only. So every web developer would pay them. Sounds like a nice plan.
Appreciate you making a vid explaining this cuz I also didn't know what people were talking about in twitter
Nice video, will include it in tomorrow's newsletter 👌
Tom Sherman! What a legend
Thicken Nugget approved
@@tom-sherman The man, the myth, the legend!
With more power, comes more responsibility
the secret is in the client side of course it's no surprise that you can see it in your browser. Just keep it in the server side. It's pretty simple to prevent this security issue.
it's really simple: every server action call is a separate http request that doesn't have access to any state of the server (assuming you are running serverless/edge, and it probably treats it independently even if you have a dedicated machine). Anything involved in a closure is treated like an argument. imo, it's better to explicitly pass them as arguments instead of hiding it behind a closure.
I don't get it. Why would anyone place it within the component/closure not in the server function? Is there a use case for doing this?
From what i get, is that you are right. No one should place it within the component and the right thing to do is to put it directly in the server function as he showed in the end of the video. The purpose of this video is just to warn people that if you put it inside the compoent function things can be leaked. This is just a video to prevent a flaw that have been fund on this alpha.
People make mistakes and this is a mistake that shouldn't expose serious credentials. Let's hope it gets fixed or a warning come beta time.
@@MrBrandenS why should this be fixed. There are lots of ways to leak your keys. Why should this be treated any differently? Anyone making this mistake is probably not working on a serious app anyway.
@@avi7278 elitism much? This is a simple mistake that could cause leaking a variable you think should only live on the server but is sent to the client. It’s much harder to make this mistake with a rest api because the api only returns what your explicitly specify as a return value. Next is exposing variables you never explicitly expose
This is basically the equivalent of doing const secret = fetch(/my/secret) in your react and that result gets bundled with the frontend. Closures are important in js for this and many other reasons.
when you define your screts inside the function
they don't appear inside the payload
if that means they are not sent to the client
why wouldn't you define the secrets inside server actions ?
They should probably only be defined in the server actions. This is just an example of what can go wrong if you’re not careful
Scary stuff 🫣
If you are building a long-term project, PLEASE go with an Express RESTful API + React SPA (Vite swc) + Zustand + React-Query. This stack is tried and true and will not screw you over. Don't chase the fancy new thing. Go for stability and reliability!
or T3 stack + supabase
1:30 curios how you toggle between screens here without showing the app switcher. Are you doing that with a specific program or utility or is that being done some how with OBS?
I three finger swipe on max using virtual desktops
I am a bit confused... how is the secret being passed to the backend in the first 'safe' example?
it's state that is serialized. basically the Home component is async, so it loads up on the server and renders some html. The secret is loaded too, but that secret is basically some state of your component that, because it's declared and assigned there, next will assume it will be needed in the rendering process and possibly in the client as well, so it's probably stored as a json string somewhere in the serialized response (i'd suggest always checking the actual rendered html in the browser to make sure you're not leaking anything)
@@arpadgabor oo I see, didn't notice the async... Mm yes this does seem a bit error prone.
But as the secret is in the serialized state in the first exampe, wouldn't that mean the secret is also visible there? It's not encrypted or anything right?
Thanks for this!
interesting, aside from any issues that come from using server actions in alpha, what will t3 stack look like? will trpc even be needed once server actions become the norm? atleast not for mutations of any kind 🤔
Idk if tRPc will be as useful. It was basically a way to get fully typesafe code, but with server actions we get that already
color theme?
Just a note. Those aren’t the stable server components. They are server actions running inside client components and it’s in alpha still. If that becomes stable it would be cool.
Excellent video
Is server action still unsafe to use in production?
It’s still alpha, so 🤷♂️
Imo all of these alpha and beta features seriously need to be removed from the main release package and instead be added to packages named ”13.4.0-beta-{major}.{minor}" or something so that people aren't using these features in production unless the package version explicitly states that it's the beta/alpha version. Having these in the main package seems really weird to me.
I do agree, if it’s alpha do not put in the main release. In their defense you can not uses these features unless you set a flag to true in the next config, so it’s fine imo
Am I the only one who thinks that we don't need 'server actions'?
Like seriously, what's wrong good ole JSON?
I get that you can't really upload files with JSON, but with Next those files aren't persisted anyways... Plus, we figured this out with the whole pre-signed URLs thing.
This is what u should not do using server actions. Its not much of a vulnerability!!
U can always see the payload ig
I just can't see why someone would connect to a DB or do complex stuff with this server actions thing.
We are already seeing some bad things about serverless, why should we go deeper?
Not sure what you mean. How else will you store data when someone submits a form?
Not that scary imo. If you’re accessing a secret in code that’s being returned to the client (eg JSX) you’re just asking for it
What code is being returned to the client? The server action is ran on the server, not the client.
You are fetching the secret inside your Home component, which means that code is being run on both the server AND the client.
This being called a security vulnerability is just a failure to understand how Next executes your component code. Which don’t get me wrong, is perfectly valid criticism of Next but has nothing to do with Server Actions.
@@Reohh the component is a server rendered component, the secret does not get sent to the frontend at all. The server component is built to run the jsx on the backend so it only sends the html. The hydration part only happens with client components
@@WebDevCody put it this way: if your `getSecret` was implemented as `return Math.random()` and you called `getSecret` at the time the server component was served, even if the server action is only being executed on the server, the only way for your server action to be guaranteed to have the same "secret" you randomly generated at serve-time is by having your server component communicate the secret to the browser and the browser to the server action. you can't expect the closure's state (ie the `const secret`) to be preserved across both the synchronously served server component and the asynchronously executed server action *_unless_* you allow the browser, being the intermediary between the serving of the server component and executing of the server action, to preserve that state for you (eg what if you have a distributed architecture where the server component is served in the US but when the user calls the server action, they're in Europe?)
the fix for this is to not allow secrets to cross "runtime" boundaries. we have several different runtime contexts: server (at server component serve-time), browser, and server action (at server-action execution time). when you try to create a secret (or any value for that matter) in one context but access it in another, that secret necessarily must be exposed, at least to the network communications. when I think about it this way, the answer to this is clearly to keep the "const secret = await getSecret" _inside_ the server action
This is a foot gun, but its not at all surprising or counterintuitive. If you remove the server action it's so obvious you are pulling a secret into a component! Why would you expect that secret to ever be excluded from client code if you did this? I guess the point is that you wouldn't do it on purpose, but it would be a careless mistake.
Idk if you fetch the secret in the server component, it won’t be sent to the frontend from what I can tell. The fact that you define the server action as an inner function causes it to be exposed. That’s not intuitive
@@WebDevCody oooooooooooooooooooooh Im dead wrong. I thought this was a client component. Yup you're 100% right this is super unintuitive and dangerous.
ive been saying this for a while injecting sql into components without a safe middleware is just asking for problems
Ty
lets goooooooooo
an eslint rule is going to be necessary if they don't change this
Absolutely, or force server actions to be separate files or something
It's far from production ready
Yeah, it’s in alpha
Guys any other good RUclipsrs like Cody and theo to watch 🎉🎉🎉
I'm not even against server action as a concept but wtf with that stupid hack of an API is "use server"? Like someone at facebook get paid to come up with that shit?
I think they jumped the gun on releasing all of this... NextJS releasing with a canary version of React? IDK...
It’s alpha, so it’s fine, just don’t use it in prod yet
@@WebDevCody Tagged alpha for a reason.
@@frenchButt44 yup mentioned in video
onest
twoest
This is alpha, come on. Let's not just talk bad things about Next just because of an alpha feature
Why is an alpha feature in a production version release?
@@WebDevCody that's their model. It is an opt-in feature that you can enable at any time, in any project to experiment it. No need to switch branches or all that fancy stuff, just change the next config and you can experiment every testing feature
@@lucas.p.f it’s at least ok to point it out so it can be improved, is it not?
@@WebDevCody of course! My comment was not directed at you in any way, as you were only helping. It was directed to some people that is hating on Vercel for quite some time and using this as an argument to trash talk about them
Angular is the matured professional framework, it has simple syntax than react. React is hard to understand, the DX of react is horrible.
React is a child play. When it comes to serious enterprise app development, Angular comes in glory.
React has brought shame to JavaScript community by making web development unnecessarily complicated.
What are you talking about 😂?
This is completely untrue and the data does not support your statement
Everyone, just ignore this person. I have seen this exact account under many React videos. Don't listen to him, he is not here to make the web better, he is only here to trash on libraries/frameworks like React & Svelte and blame them for the web being bad.
@@Dev-Siri just look at his account name, lol
@@eduardoromaguera9707 what is so special about the name?
The first example you show also leaks btw! action={doSomething(secret)} is still closing on secret.
I’ll retest but I didn’t find the secret in any of the frontend html or JavaScript when I did that approach, because react will run through your component once and evaluate everything and not send it to the server. It’s the same reason why we can do prisma or sql queries inside the server render component and not have it leak secrets.
@@WebDevCody it is leaking. You’re not using the variable in the function - hence it is not included in the rendered form. If you ‘console.log(secret)’ inside ‘doSomething’ (1:24) you will see that it leaks. This has nothing to do with sql or prisma, it’s to do with closures.
@@hhueston leaked where?
Your secret will be injected into the html form as a hidden input